mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(logrocket): add LogRocket integration (#6678)
* feat(logrocket): add LogRocket integration * improvement(logrocket): fail loudly on a non-numeric identify timestamp and cover releases in the catalog copy * fix(logrocket): require a highlights identity and treat pagination cursors as opaque strings * fix(logrocket): trim request fields so whitespace-only input fails validation * fix(logrocket): declare the release version in the block inputs map
This commit is contained in:
@@ -1518,12 +1518,12 @@ export function InputIcon(props: SVGProps<SVGSVGElement>) {
|
||||
export function StartIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
width='26'
|
||||
height='16'
|
||||
viewBox='0 0 26 16'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d='M7.8 13C9.23 13 10.45 12.49 11.47 11.47C12.49 10.45 13 9.23 13 7.8C13 6.37 12.49 5.15 11.47 4.13C10.45 3.11 9.23 2.6 7.8 2.6C6.37 2.6 5.15 3.11 4.13 4.13C3.11 5.15 2.6 6.37 2.6 7.8C2.6 9.23 3.11 10.45 4.13 11.47C5.15 12.49 6.37 13 7.8 13ZM7.8 15.6C5.63 15.6 3.79 14.84 2.28 13.33C0.76 11.81 0 9.97 0 7.8C0 5.63 0.76 3.79 2.28 2.28C3.79 0.76 5.63 0 7.8 0C9.75 0 11.45 0.62 12.89 1.85C14.33 3.09 15.2 4.64 15.5 6.5H24.7C25.07 6.5 25.38 6.62 25.63 6.87C25.88 7.12 26 7.43 26 7.8C26 8.17 25.87 8.48 25.63 8.73C25.38 8.98 25.07 9.1 24.7 9.1H15.5C15.2 10.96 14.33 12.51 12.89 13.75C11.44 14.98 9.75 15.6 7.8 15.6Z'
|
||||
@@ -9035,6 +9035,23 @@ export function LogfireIcon(props: SVGProps<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function LogRocketIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 19 28' fill='none' role='img' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='currentColor'
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
d='M6.066 3.156A10.53 10.53 0 0 1 9.122 0a10.294 10.294 0 0 1 3.016 3.094 15.59 15.59 0 0 1 2.93 9.777c.637.513 1.293 1.006 1.918 1.53a3.46 3.46 0 0 1 1.104 3.189c-.302 1.457-.592 2.918-.911 4.372a1.214 1.214 0 0 1-1.848.61c-1.027-.825-2.027-1.678-3.05-2.504a4.684 4.684 0 0 1-2.891 1.255 4.678 4.678 0 0 1-3.385-1.22c-.735.541-1.419 1.191-2.138 1.772-.315.31-.666.58-1.046.806a1.215 1.215 0 0 1-1.603-.785c-.329-1.422-.672-2.839-.99-4.263a3.453 3.453 0 0 1 1.163-3.321c.559-.45 1.125-.893 1.694-1.331.159-.08.08-.261.087-.401a15.615 15.615 0 0 1 2.9-9.42m1.007 4.402a2.395 2.395 0 0 0 .21 3.173 2.636 2.636 0 0 0 3.603.075 2.398 2.398 0 0 0 .636-2.634 2.55 2.55 0 0 0-2.14-1.59 2.6 2.6 0 0 0-2.31.974'
|
||||
/>
|
||||
<path
|
||||
fill='currentColor'
|
||||
d='M5.712 23.082a.605.605 0 0 1 .896-.485 5.778 5.778 0 0 0 5.03 0 .61.61 0 0 1 .896.45c.005.89.005 1.78 0 2.67a.602.602 0 0 1-.94.436c-.267-.226-.508-.48-.764-.719-.407.762-.789 1.534-1.199 2.294a.61.61 0 0 1-1.012.006c-.41-.761-.79-1.538-1.206-2.299-.253.24-.494.494-.761.72a.603.603 0 0 1-.94-.442c-.007-.878 0-1.756 0-2.634M9.102 10.259a1.22 1.22 0 0 0 1.248-1.192v-.008a1.221 1.221 0 0 0-1.24-1.2h-.008A1.22 1.22 0 0 0 7.855 9.05v.008a1.22 1.22 0 0 0 1.24 1.2h.007Z'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function SmartleadIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Maps block types to their icon component references
|
||||
|
||||
import type { ComponentType, SVGProps } from 'react'
|
||||
import { Library } from '@sim/emcn/icons'
|
||||
import { Library, Rocket } from '@sim/emcn/icons'
|
||||
import {
|
||||
A2AIcon,
|
||||
AgentMailIcon,
|
||||
@@ -136,6 +136,7 @@ import {
|
||||
LinkupIcon,
|
||||
LinqIcon,
|
||||
LogfireIcon,
|
||||
LogRocketIcon,
|
||||
LoopsIcon,
|
||||
LumaIcon,
|
||||
MailchimpIcon,
|
||||
@@ -205,7 +206,6 @@ import {
|
||||
ServiceNowIcon,
|
||||
SftpIcon,
|
||||
ShopifyIcon,
|
||||
SimDeploymentsIcon,
|
||||
SimilarwebIcon,
|
||||
SimTriggerIcon,
|
||||
SixtyfourIcon,
|
||||
@@ -309,7 +309,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
datadog: DatadogIcon,
|
||||
datagma: DatagmaIcon,
|
||||
daytona: DaytonaIcon,
|
||||
deployments: SimDeploymentsIcon,
|
||||
deployments: Rocket,
|
||||
devin: DevinIcon,
|
||||
discord: DiscordIcon,
|
||||
docusign: DocuSignIcon,
|
||||
@@ -414,6 +414,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
linkup: LinkupIcon,
|
||||
linq: LinqIcon,
|
||||
logfire: LogfireIcon,
|
||||
logrocket: LogRocketIcon,
|
||||
logs: Library,
|
||||
logs_v2: Library,
|
||||
loops: LoopsIcon,
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
---
|
||||
title: LogRocket
|
||||
description: Summarize sessions, manage users, and tag releases in LogRocket
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="logrocket"
|
||||
color="#764ABC"
|
||||
/>
|
||||
|
||||
{/* MANUAL-CONTENT-START:intro */}
|
||||
[LogRocket](https://logrocket.com/) is a session replay and product analytics platform for frontend applications. It records what users actually did — clicks, navigation, network requests, console output, and application state — so teams can see the exact path that led to a bug, a drop-off, or a support ticket instead of asking the customer to reproduce it.
|
||||
|
||||
With LogRocket, you can:
|
||||
|
||||
- **Summarize sessions with AI**: Galileo Highlights reads a user's sessions and answers a plain-English question about them, returning a markdown summary plus per-session breakdowns.
|
||||
- **Identify users**: Attach names, emails, and custom traits to a user so sessions can be segmented by plan, lifecycle stage, or account value.
|
||||
- **Export session data**: Pull download URLs for JSON Lines session exports and load them into a warehouse.
|
||||
- **Audit session access**: Page through the audit log to see who viewed which sessions and when.
|
||||
- **Tag releases**: Register a deployed version so uploaded source maps decode its stack traces.
|
||||
|
||||
Sim's LogRocket integration lets your agents run these operations programmatically. Use it to enrich a support ticket with a session summary, turn a vague bug report into reproduction steps, keep user traits in sync with your CRM, or register a release as part of a deploy workflow.
|
||||
|
||||
Highlights requests are asynchronous: **Request Highlights** returns an ID and **Get Highlights** reports `PENDING` until generation finishes (typically one to three minutes), then `READY` or `FAILED`. Poll it rather than expecting the summary immediately.
|
||||
|
||||
LogRocket has no REST API for querying sessions, issues, or metrics directly — that data is available through their [MCP server](https://docs.logrocket.com/docs/mcp) at `https://mcp.logrocket.com/mcp`, which you can add to Sim as an MCP server connection alongside this block.
|
||||
{/* MANUAL-CONTENT-END */}
|
||||
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate LogRocket into your workflow to request AI session highlights for a user, poll for the result, list exported session files, read the audit log, create or update user profiles, and register releases so source maps decode their stack traces.
|
||||
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
### LogRocket Request Highlights
|
||||
|
||||
Start a Galileo session highlights job for a user. Returns a request ID to poll with LogRocket's Get Highlights operation.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `userEmail` | string | No | Email of the user to summarize. Required if no user ID is given. |
|
||||
| `userID` | string | No | ID of the user to summarize. Required if no email is given. |
|
||||
| `question` | string | No | Question to focus the highlights on |
|
||||
| `startMs` | string | No | Start of the session window, in milliseconds since epoch |
|
||||
| `endMs` | string | No | End of the session window, in milliseconds since epoch |
|
||||
| `webhookURL` | string | No | URL notified when the highlights job finishes |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Request ID used to retrieve the highlights result |
|
||||
|
||||
### LogRocket Get Highlights
|
||||
|
||||
Retrieve the result of a Galileo session highlights request. Status is PENDING until generation finishes, then READY or FAILED.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `id` | string | Yes | Request ID returned by the Request Highlights operation |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `status` | string | Job status: PENDING, READY, or FAILED |
|
||||
| `requestID` | string | ID of the highlights request |
|
||||
| `appID` | string | LogRocket project the request belongs to |
|
||||
| `highlights` | string | Markdown summary across the matched sessions. Present when status is READY. |
|
||||
| `sessions` | array | Per-session highlights |
|
||||
| ↳ `recordingID` | string | LogRocket recording ID |
|
||||
| ↳ `sessionID` | number | Session number within the recording |
|
||||
| ↳ `highlights` | string | Highlights for this session |
|
||||
|
||||
### LogRocket List Exported Sessions
|
||||
|
||||
List exported session files from the LogRocket Data Export API. Returns download URLs for JSON Lines exports, oldest first, plus a cursor for the next page.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `cursor` | string | No | Cursor from a previous page, used to fetch newer sessions |
|
||||
| `limit` | string | No | Results per page. Defaults to 10, maximum 100. |
|
||||
| `date` | string | No | Unix timestamp in milliseconds to start listing from |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `sessions` | array | Exported session files |
|
||||
| ↳ `url` | string | Download URL for the JSON Lines export file |
|
||||
| `cursor` | string | Opaque cursor for the next page of results |
|
||||
|
||||
### LogRocket Get Audit Logs
|
||||
|
||||
Export audit log entries from LogRocket, recording who viewed sessions and what actions were taken. Paginated with a cursor.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `limit` | string | No | Number of audit log records to return |
|
||||
| `cursor` | string | No | Cursor from a previous page, used to fetch the next page |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `logs` | array | Audit log entries |
|
||||
| ↳ `time` | string | Formatted timestamp of the action |
|
||||
| ↳ `createdDate` | string | ISO 8601 timestamp of the action |
|
||||
| ↳ `user` | string | Email or system ID of the actor |
|
||||
| ↳ `action` | string | Action taken, e.g. Viewed session |
|
||||
| ↳ `description` | string | Action details, e.g. the session ID |
|
||||
| `cursor` | string | Opaque cursor for the next page of results |
|
||||
| `hasNext` | boolean | Whether more audit logs exist beyond this page |
|
||||
|
||||
### LogRocket Identify User
|
||||
|
||||
Create or update a LogRocket user profile with demographic, financial, and engagement traits.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `userId` | string | Yes | ID of the user to create or update |
|
||||
| `name` | string | No | Display name of the user. Maximum 1024 characters. |
|
||||
| `email` | string | No | Email of the user. Maximum 1024 characters. |
|
||||
| `timestamp` | string | No | Unix timestamp in milliseconds describing when the submitted data was true |
|
||||
| `traits` | string | No | JSON object of custom traits. Each key and value is limited to 1024 characters and stored as a string. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `userID` | string | ID of the created or updated user |
|
||||
| `name` | string | Display name stored on the profile |
|
||||
| `email` | string | Email stored on the profile |
|
||||
| `traits` | json | Custom traits stored on the profile, with every value coerced to a string |
|
||||
|
||||
### LogRocket Create Release
|
||||
|
||||
Register a release version in LogRocket so uploaded source maps can decode stack traces for it. Fails with a conflict if the version already exists.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | LogRocket API key |
|
||||
| `orgId` | string | Yes | LogRocket organization ID |
|
||||
| `appId` | string | Yes | LogRocket project \(app\) ID |
|
||||
| `apiHost` | string | No | API host override for Private Cloud deployments |
|
||||
| `version` | string | Yes | Release version to register, e.g. 1.2.3 or a commit SHA |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `version` | string | Release version that was registered |
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
"linkup",
|
||||
"linq",
|
||||
"logfire",
|
||||
"logrocket",
|
||||
"logs",
|
||||
"loops",
|
||||
"luma",
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
import { LogRocketIcon } from '@/components/icons'
|
||||
import { AuthMode, type BlockConfig, type BlockMeta, IntegrationType } from '@/blocks/types'
|
||||
|
||||
/**
|
||||
* A highlights request identifies its subject by email or user ID — either one
|
||||
* alone is a valid identity, so the card sentence takes whichever is filled.
|
||||
* These are mutually exclusive alternates rather than a canonical
|
||||
* basic/advanced pair.
|
||||
*/
|
||||
const HIGHLIGHTS_IDENTITY_FIELD = ['highlightsUserEmail', 'highlightsUserId'] as const
|
||||
|
||||
export const LogRocketBlock: BlockConfig = {
|
||||
type: 'logrocket',
|
||||
name: 'LogRocket',
|
||||
description: 'Summarize sessions, manage users, and tag releases in LogRocket',
|
||||
longDescription:
|
||||
'Integrate LogRocket into your workflow to request AI session highlights for a user, poll for the result, list exported session files, read the audit log, create or update user profiles, and register releases so source maps decode their stack traces.',
|
||||
docsLink: 'https://docs.sim.ai/integrations/logrocket',
|
||||
category: 'tools',
|
||||
integrationType: IntegrationType.Observability,
|
||||
bgColor: '#764ABC',
|
||||
icon: LogRocketIcon,
|
||||
authMode: AuthMode.ApiKey,
|
||||
canvasPresentation: {
|
||||
defaultTitle: 'LogRocket',
|
||||
sentences: {
|
||||
byOperation: {
|
||||
request_highlights: [
|
||||
{ text: 'Summarize sessions for', field: HIGHLIGHTS_IDENTITY_FIELD, core: true },
|
||||
{ text: 'asking', field: 'question' },
|
||||
],
|
||||
get_highlights: [
|
||||
{ text: 'Get highlights for request', field: 'highlightsRequestId', core: true },
|
||||
],
|
||||
list_exported_sessions: [
|
||||
'List exported sessions',
|
||||
{ text: ', up to', field: 'exportLimit', after: 'files' },
|
||||
],
|
||||
get_audit_logs: [
|
||||
'Read audit logs',
|
||||
{ text: ', up to', field: 'auditLimit', after: 'entries' },
|
||||
],
|
||||
identify_user: [
|
||||
{ text: 'Update LogRocket profile for', field: 'profileUserId', core: true },
|
||||
],
|
||||
create_release: [{ text: 'Register release', field: 'version', core: true }],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Request Highlights', id: 'request_highlights' },
|
||||
{ label: 'Get Highlights', id: 'get_highlights' },
|
||||
{ label: 'List Exported Sessions', id: 'list_exported_sessions' },
|
||||
{ label: 'Get Audit Logs', id: 'get_audit_logs' },
|
||||
{ label: 'Identify User', id: 'identify_user' },
|
||||
{ label: 'Create Release', id: 'create_release' },
|
||||
],
|
||||
value: () => 'request_highlights',
|
||||
},
|
||||
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter your LogRocket API key',
|
||||
password: true,
|
||||
},
|
||||
{
|
||||
id: 'orgId',
|
||||
title: 'Organization ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Your LogRocket organization ID',
|
||||
},
|
||||
{
|
||||
id: 'appId',
|
||||
title: 'Project ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Your LogRocket project (app) ID',
|
||||
},
|
||||
{
|
||||
id: 'apiHost',
|
||||
title: 'API Host',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://api.logrocket.com',
|
||||
mode: 'advanced',
|
||||
},
|
||||
|
||||
// --- Request Highlights fields ---
|
||||
{
|
||||
id: 'highlightsUserEmail',
|
||||
title: 'User Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Email of the user (required if no User ID)',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
},
|
||||
{
|
||||
id: 'highlightsUserId',
|
||||
title: 'User ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'User ID (required if no User Email)',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
},
|
||||
{
|
||||
id: 'question',
|
||||
title: 'Question',
|
||||
type: 'long-input',
|
||||
placeholder: 'e.g., Why did this user fail to complete checkout?',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
},
|
||||
{
|
||||
id: 'startMs',
|
||||
title: 'Start Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'Milliseconds since epoch',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt:
|
||||
'Generate a timestamp in milliseconds since epoch. Return ONLY the number - no explanations, no extra text.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endMs',
|
||||
title: 'End Time',
|
||||
type: 'short-input',
|
||||
placeholder: 'Milliseconds since epoch',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt:
|
||||
'Generate a timestamp in milliseconds since epoch. Return ONLY the number - no explanations, no extra text.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'webhookURL',
|
||||
title: 'Webhook URL',
|
||||
type: 'short-input',
|
||||
placeholder: 'Notified when the highlights job finishes',
|
||||
condition: { field: 'operation', value: 'request_highlights' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
|
||||
// --- Get Highlights fields ---
|
||||
{
|
||||
id: 'highlightsRequestId',
|
||||
title: 'Request ID',
|
||||
type: 'short-input',
|
||||
required: { field: 'operation', value: 'get_highlights' },
|
||||
placeholder: 'ID returned by Request Highlights',
|
||||
condition: { field: 'operation', value: 'get_highlights' },
|
||||
},
|
||||
|
||||
// --- List Exported Sessions fields ---
|
||||
{
|
||||
id: 'exportLimit',
|
||||
title: 'Limit',
|
||||
type: 'short-input',
|
||||
placeholder: 'Default 10, maximum 100',
|
||||
condition: { field: 'operation', value: 'list_exported_sessions' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'exportCursor',
|
||||
title: 'Cursor',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cursor from a previous page',
|
||||
condition: { field: 'operation', value: 'list_exported_sessions' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'exportDate',
|
||||
title: 'Start Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'Milliseconds since epoch',
|
||||
condition: { field: 'operation', value: 'list_exported_sessions' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt:
|
||||
'Generate a timestamp in milliseconds since epoch. Return ONLY the number - no explanations, no extra text.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
|
||||
// --- Get Audit Logs fields ---
|
||||
{
|
||||
id: 'auditLimit',
|
||||
title: 'Limit',
|
||||
type: 'short-input',
|
||||
placeholder: 'Number of audit log records to return',
|
||||
condition: { field: 'operation', value: 'get_audit_logs' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'auditCursor',
|
||||
title: 'Cursor',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cursor from a previous page',
|
||||
condition: { field: 'operation', value: 'get_audit_logs' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
|
||||
// --- Identify User fields ---
|
||||
{
|
||||
id: 'profileUserId',
|
||||
title: 'User ID',
|
||||
type: 'short-input',
|
||||
required: { field: 'operation', value: 'identify_user' },
|
||||
placeholder: 'ID of the user to create or update',
|
||||
condition: { field: 'operation', value: 'identify_user' },
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
title: 'Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Display name (max 1024 characters)',
|
||||
condition: { field: 'operation', value: 'identify_user' },
|
||||
},
|
||||
{
|
||||
id: 'email',
|
||||
title: 'Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Email address (max 1024 characters)',
|
||||
condition: { field: 'operation', value: 'identify_user' },
|
||||
},
|
||||
{
|
||||
id: 'traits',
|
||||
title: 'Traits',
|
||||
type: 'long-input',
|
||||
placeholder: '{"plan": "free", "favoriteColor": "blue"}',
|
||||
condition: { field: 'operation', value: 'identify_user' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt:
|
||||
'Generate a JSON object of custom user traits for LogRocket. Keys and values are limited to 1024 characters. Return ONLY the JSON object - no explanations, no extra text.',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'timestamp',
|
||||
title: 'Timestamp',
|
||||
type: 'short-input',
|
||||
placeholder: 'Milliseconds since epoch',
|
||||
condition: { field: 'operation', value: 'identify_user' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt:
|
||||
'Generate a timestamp in milliseconds since epoch. Return ONLY the number - no explanations, no extra text.',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
|
||||
// --- Create Release fields ---
|
||||
{
|
||||
id: 'version',
|
||||
title: 'Version',
|
||||
type: 'short-input',
|
||||
required: { field: 'operation', value: 'create_release' },
|
||||
placeholder: 'e.g., 1.2.3 or a commit SHA',
|
||||
condition: { field: 'operation', value: 'create_release' },
|
||||
},
|
||||
],
|
||||
|
||||
tools: {
|
||||
access: [
|
||||
'logrocket_request_highlights',
|
||||
'logrocket_get_highlights',
|
||||
'logrocket_list_exported_sessions',
|
||||
'logrocket_get_audit_logs',
|
||||
'logrocket_identify_user',
|
||||
'logrocket_create_release',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => `logrocket_${params.operation}`,
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'request_highlights':
|
||||
if (params.highlightsUserEmail) result.userEmail = params.highlightsUserEmail
|
||||
if (params.highlightsUserId) result.userID = params.highlightsUserId
|
||||
break
|
||||
|
||||
case 'get_highlights':
|
||||
if (params.highlightsRequestId) result.id = params.highlightsRequestId
|
||||
break
|
||||
|
||||
case 'list_exported_sessions':
|
||||
if (params.exportLimit) result.limit = params.exportLimit
|
||||
if (params.exportCursor) result.cursor = params.exportCursor
|
||||
if (params.exportDate) result.date = params.exportDate
|
||||
break
|
||||
|
||||
case 'get_audit_logs':
|
||||
if (params.auditLimit) result.limit = params.auditLimit
|
||||
if (params.auditCursor) result.cursor = params.auditCursor
|
||||
break
|
||||
|
||||
case 'identify_user':
|
||||
if (params.profileUserId) result.userId = params.profileUserId
|
||||
break
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
apiKey: { type: 'string', description: 'LogRocket API key' },
|
||||
orgId: { type: 'string', description: 'LogRocket organization ID' },
|
||||
appId: { type: 'string', description: 'LogRocket project (app) ID' },
|
||||
apiHost: { type: 'string', description: 'API host override for Private Cloud deployments' },
|
||||
highlightsUserEmail: { type: 'string', description: 'Email of the user to summarize' },
|
||||
highlightsUserId: { type: 'string', description: 'ID of the user to summarize' },
|
||||
question: { type: 'string', description: 'Question to focus the highlights on' },
|
||||
startMs: { type: 'string', description: 'Session window start, in milliseconds since epoch' },
|
||||
endMs: { type: 'string', description: 'Session window end, in milliseconds since epoch' },
|
||||
webhookURL: { type: 'string', description: 'URL notified when the highlights job finishes' },
|
||||
highlightsRequestId: { type: 'string', description: 'ID of a highlights request to retrieve' },
|
||||
exportLimit: { type: 'string', description: 'Exported sessions per page' },
|
||||
exportCursor: { type: 'string', description: 'Exported sessions pagination cursor' },
|
||||
exportDate: { type: 'string', description: 'Exported sessions start timestamp' },
|
||||
auditLimit: { type: 'string', description: 'Audit log records per page' },
|
||||
auditCursor: { type: 'string', description: 'Audit log pagination cursor' },
|
||||
profileUserId: { type: 'string', description: 'ID of the user to create or update' },
|
||||
name: { type: 'string', description: 'Display name of the user' },
|
||||
email: { type: 'string', description: 'Email of the user' },
|
||||
traits: { type: 'string', description: 'Custom user traits JSON object' },
|
||||
timestamp: {
|
||||
type: 'string',
|
||||
description: 'Profile data timestamp in milliseconds since epoch',
|
||||
},
|
||||
version: { type: 'string', description: 'Release version to register' },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Highlights request ID (request_highlights)',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Highlights job status: PENDING, READY, or FAILED (get_highlights)',
|
||||
},
|
||||
requestID: {
|
||||
type: 'string',
|
||||
description: 'ID of the highlights request (get_highlights)',
|
||||
},
|
||||
appID: {
|
||||
type: 'string',
|
||||
description: 'LogRocket project the request belongs to (get_highlights)',
|
||||
},
|
||||
highlights: {
|
||||
type: 'string',
|
||||
description: 'Markdown summary across the matched sessions (get_highlights)',
|
||||
},
|
||||
sessions: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Per-session highlights (recordingID, sessionID, highlights) for get_highlights, or exported file URLs for list_exported_sessions',
|
||||
},
|
||||
logs: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Audit log entries (time, createdDate, user, action, description) (get_audit_logs)',
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
description: 'Opaque cursor for the next page (list_exported_sessions, get_audit_logs)',
|
||||
},
|
||||
hasNext: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more audit logs exist beyond this page (get_audit_logs)',
|
||||
},
|
||||
userID: {
|
||||
type: 'string',
|
||||
description: 'ID of the created or updated user (identify_user)',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Display name stored on the profile (identify_user)',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
description: 'Email stored on the profile (identify_user)',
|
||||
},
|
||||
traits: {
|
||||
type: 'json',
|
||||
description: 'Custom traits stored on the profile, values coerced to strings (identify_user)',
|
||||
},
|
||||
version: {
|
||||
type: 'string',
|
||||
description: 'Release version that was registered (create_release)',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const LogRocketBlockMeta = {
|
||||
tags: ['monitoring', 'error-tracking', 'data-analytics'],
|
||||
url: 'https://logrocket.com',
|
||||
templates: [
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket session triage from support tickets',
|
||||
prompt:
|
||||
'Build a workflow that triggers on a new Zendesk ticket, requests LogRocket session highlights for the reporting user, polls until the result is ready, and posts the session summary back onto the ticket as an internal note.',
|
||||
modules: ['agent', 'workflows'],
|
||||
category: 'support',
|
||||
tags: ['support', 'automation'],
|
||||
alsoIntegrations: ['zendesk'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket churn-risk session review',
|
||||
prompt:
|
||||
'Create a scheduled workflow that reads at-risk accounts from a table, requests LogRocket session highlights for each contact, and writes the summarized friction points back to the table for the customer success team.',
|
||||
modules: ['tables', 'scheduled', 'agent', 'workflows'],
|
||||
category: 'operations',
|
||||
tags: ['analysis', 'reporting'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket bug report enrichment',
|
||||
prompt:
|
||||
'Build a workflow that triggers on a new Linear bug issue, asks LogRocket for session highlights of the affected user with the bug description as the question, and comments the session breakdown on the issue.',
|
||||
modules: ['agent', 'workflows'],
|
||||
category: 'engineering',
|
||||
tags: ['debugging', 'automation'],
|
||||
alsoIntegrations: ['linear'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket audit log compliance export',
|
||||
prompt:
|
||||
'Create a scheduled workflow that pages through the LogRocket audit log every night, writes each entry to a compliance table, and alerts Slack when a session was viewed by someone outside the approved reviewer list.',
|
||||
modules: ['tables', 'scheduled', 'agent', 'workflows'],
|
||||
category: 'operations',
|
||||
tags: ['compliance', 'monitoring'],
|
||||
alsoIntegrations: ['slack'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket session export pipeline',
|
||||
prompt:
|
||||
'Build a scheduled workflow that lists newly exported LogRocket session files, downloads each JSON Lines export, and loads the parsed events into a warehouse table for analysis.',
|
||||
modules: ['tables', 'scheduled', 'workflows'],
|
||||
category: 'operations',
|
||||
tags: ['sync', 'data-pipeline'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket profile sync from CRM',
|
||||
prompt:
|
||||
'Create a workflow that watches HubSpot contact updates and pushes the plan, lifecycle stage, and account value into LogRocket as user traits so sessions can be filtered by customer segment.',
|
||||
modules: ['agent', 'workflows'],
|
||||
category: 'operations',
|
||||
tags: ['sync', 'automation'],
|
||||
alsoIntegrations: ['hubspot'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket + Sentry incident context',
|
||||
prompt:
|
||||
'Build a workflow that triggers on a new Sentry issue, requests LogRocket session highlights for the impacted user, and posts a combined stack trace plus session narrative into the incident Slack channel.',
|
||||
modules: ['agent', 'workflows'],
|
||||
category: 'engineering',
|
||||
tags: ['debugging', 'monitoring'],
|
||||
alsoIntegrations: ['sentry', 'slack'],
|
||||
},
|
||||
{
|
||||
icon: LogRocketIcon,
|
||||
title: 'LogRocket release tagging on deploy',
|
||||
prompt:
|
||||
'Build a workflow that runs after a GitHub deployment succeeds, registers the deployed version as a LogRocket release so stack traces decode against it, and posts the tagged version to the release channel in Slack.',
|
||||
modules: ['agent', 'workflows'],
|
||||
category: 'engineering',
|
||||
tags: ['automation', 'ci-cd'],
|
||||
alsoIntegrations: ['github', 'slack'],
|
||||
},
|
||||
],
|
||||
skills: [
|
||||
{
|
||||
name: 'summarize-user-sessions',
|
||||
description:
|
||||
'Request LogRocket session highlights for a user, wait for the job to finish, and report what happened in their sessions.',
|
||||
content:
|
||||
'# Summarize User Sessions\n\nUse LogRocket to explain what a specific user did and where they got stuck.\n\n## Steps\n1. Identify the user by email or user ID.\n2. Optionally narrow to a time window and supply a focused question, e.g. why checkout failed.\n3. Request session highlights and keep the returned request ID.\n4. Poll for the result until the status is READY. It typically takes one to three minutes. A FAILED status means the request should be retried.\n\n## Output\nThe overall highlights summary plus the per-session breakdown, each with its recording ID. Note the time window covered.',
|
||||
},
|
||||
{
|
||||
name: 'investigate-reported-bug',
|
||||
description:
|
||||
'Pull LogRocket session highlights for the user who reported a bug and turn them into reproduction steps.',
|
||||
content:
|
||||
'# Investigate Reported Bug\n\nTurn a vague bug report into concrete reproduction steps using LogRocket sessions.\n\n## Steps\n1. Extract the reporting user email or ID and the time the problem occurred.\n2. Request session highlights for that user, scoped to a window around the report, using the bug description as the question.\n3. Wait for the result and read the per-session highlights.\n4. Map the described actions into ordered reproduction steps and note the failing step.\n\n## Output\nReproduction steps, the observed failure, and links to the relevant recording IDs.',
|
||||
},
|
||||
{
|
||||
name: 'sync-user-traits',
|
||||
description:
|
||||
'Create or update a LogRocket user profile with name, email, and custom traits so sessions can be segmented.',
|
||||
content:
|
||||
'# Sync User Traits\n\nKeep LogRocket user profiles current so sessions can be filtered by customer attributes.\n\n## Steps\n1. Determine the user ID to write to. This is the identifier LogRocket already associates with the sessions.\n2. Gather the traits to set, such as plan, lifecycle stage, or account value. Keep every key and value under 1024 characters.\n3. Optionally supply a timestamp describing when the data was true.\n4. Write the profile.\n\n## Output\nConfirm which fields were written and note that every trait value is stored as a string.',
|
||||
},
|
||||
{
|
||||
name: 'review-session-access',
|
||||
description:
|
||||
'Page through the LogRocket audit log to report who viewed sessions and what actions they took.',
|
||||
content:
|
||||
'# Review Session Access\n\nAudit who has been viewing LogRocket sessions.\n\n## Steps\n1. Read the first page of audit logs, choosing a page size.\n2. While the response reports more pages, follow the returned cursor to fetch the next page.\n3. Group entries by actor and action to see who viewed what.\n\n## Output\nA per-actor summary of actions with timestamps, plus any access that looks unexpected.',
|
||||
},
|
||||
{
|
||||
name: 'collect-exported-sessions',
|
||||
description:
|
||||
'List LogRocket data export files and collect their download URLs for downstream processing.',
|
||||
content:
|
||||
'# Collect Exported Sessions\n\nGather the session export files LogRocket has produced.\n\n## Steps\n1. List exported sessions, optionally starting from a timestamp and choosing a page size of up to 100.\n2. Note that results come back oldest first, and follow the returned cursor to page forward.\n3. Collect the download URL for each export file. Each file is JSON Lines.\n\n## Output\nThe list of export URLs, the range they cover, and the cursor to resume from next run.',
|
||||
},
|
||||
],
|
||||
} as const satisfies BlockMeta
|
||||
@@ -181,6 +181,7 @@ import { LinkedInBlock, LinkedInBlockMeta } from '@/blocks/blocks/linkedin'
|
||||
import { LinkupBlock, LinkupBlockMeta } from '@/blocks/blocks/linkup'
|
||||
import { LinqBlock, LinqBlockMeta } from '@/blocks/blocks/linq'
|
||||
import { LogfireBlock, LogfireBlockMeta } from '@/blocks/blocks/logfire'
|
||||
import { LogRocketBlock, LogRocketBlockMeta } from '@/blocks/blocks/logrocket'
|
||||
import { LogsBlock, LogsV2Block } from '@/blocks/blocks/logs'
|
||||
import { LoopsBlock, LoopsBlockMeta } from '@/blocks/blocks/loops'
|
||||
import { LumaBlock, LumaBlockMeta } from '@/blocks/blocks/luma'
|
||||
@@ -517,6 +518,7 @@ export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
|
||||
linkup: LinkupBlock,
|
||||
linq: LinqBlock,
|
||||
logfire: LogfireBlock,
|
||||
logrocket: LogRocketBlock,
|
||||
logs: LogsBlock,
|
||||
logs_v2: LogsV2Block,
|
||||
loops: LoopsBlock,
|
||||
@@ -826,6 +828,7 @@ export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
|
||||
linkup: LinkupBlockMeta,
|
||||
linq: LinqBlockMeta,
|
||||
logfire: LogfireBlockMeta,
|
||||
logrocket: LogRocketBlockMeta,
|
||||
loops: LoopsBlockMeta,
|
||||
luma: LumaBlockMeta,
|
||||
mailchimp: MailchimpBlockMeta,
|
||||
|
||||
@@ -9035,6 +9035,23 @@ export function LogfireIcon(props: SVGProps<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function LogRocketIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 19 28' fill='none' role='img' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='currentColor'
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
d='M6.066 3.156A10.53 10.53 0 0 1 9.122 0a10.294 10.294 0 0 1 3.016 3.094 15.59 15.59 0 0 1 2.93 9.777c.637.513 1.293 1.006 1.918 1.53a3.46 3.46 0 0 1 1.104 3.189c-.302 1.457-.592 2.918-.911 4.372a1.214 1.214 0 0 1-1.848.61c-1.027-.825-2.027-1.678-3.05-2.504a4.684 4.684 0 0 1-2.891 1.255 4.678 4.678 0 0 1-3.385-1.22c-.735.541-1.419 1.191-2.138 1.772-.315.31-.666.58-1.046.806a1.215 1.215 0 0 1-1.603-.785c-.329-1.422-.672-2.839-.99-4.263a3.453 3.453 0 0 1 1.163-3.321c.559-.45 1.125-.893 1.694-1.331.159-.08.08-.261.087-.401a15.615 15.615 0 0 1 2.9-9.42m1.007 4.402a2.395 2.395 0 0 0 .21 3.173 2.636 2.636 0 0 0 3.603.075 2.398 2.398 0 0 0 .636-2.634 2.55 2.55 0 0 0-2.14-1.59 2.6 2.6 0 0 0-2.31.974'
|
||||
/>
|
||||
<path
|
||||
fill='currentColor'
|
||||
d='M5.712 23.082a.605.605 0 0 1 .896-.485 5.778 5.778 0 0 0 5.03 0 .61.61 0 0 1 .896.45c.005.89.005 1.78 0 2.67a.602.602 0 0 1-.94.436c-.267-.226-.508-.48-.764-.719-.407.762-.789 1.534-1.199 2.294a.61.61 0 0 1-1.012.006c-.41-.761-.79-1.538-1.206-2.299-.253.24-.494.494-.761.72a.603.603 0 0 1-.94-.442c-.007-.878 0-1.756 0-2.634M9.102 10.259a1.22 1.22 0 0 0 1.248-1.192v-.008a1.221 1.221 0 0 0-1.24-1.2h-.008A1.22 1.22 0 0 0 7.855 9.05v.008a1.22 1.22 0 0 0 1.24 1.2h.007Z'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function SmartleadIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Maps block types to their icon component references for the integrations page
|
||||
|
||||
import type { ComponentType, SVGProps } from 'react'
|
||||
import { Library } from '@sim/emcn/icons'
|
||||
import { Library, Rocket } from '@sim/emcn/icons'
|
||||
import {
|
||||
A2AIcon,
|
||||
AgentMailIcon,
|
||||
@@ -135,6 +135,7 @@ import {
|
||||
LinkupIcon,
|
||||
LinqIcon,
|
||||
LogfireIcon,
|
||||
LogRocketIcon,
|
||||
LoopsIcon,
|
||||
LumaIcon,
|
||||
MailchimpIcon,
|
||||
@@ -203,7 +204,6 @@ import {
|
||||
ServiceNowIcon,
|
||||
SftpIcon,
|
||||
ShopifyIcon,
|
||||
SimDeploymentsIcon,
|
||||
SimilarwebIcon,
|
||||
SimTriggerIcon,
|
||||
SixtyfourIcon,
|
||||
@@ -305,7 +305,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
datadog: DatadogIcon,
|
||||
datagma: DatagmaIcon,
|
||||
daytona: DaytonaIcon,
|
||||
deployments: SimDeploymentsIcon,
|
||||
deployments: Rocket,
|
||||
devin: DevinIcon,
|
||||
discord: DiscordIcon,
|
||||
docusign: DocuSignIcon,
|
||||
@@ -402,6 +402,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
linkup: LinkupIcon,
|
||||
linq: LinqIcon,
|
||||
logfire: LogfireIcon,
|
||||
logrocket: LogRocketIcon,
|
||||
logs_v2: Library,
|
||||
loops: LoopsIcon,
|
||||
luma: LumaIcon,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"updatedAt": "2026-08-12",
|
||||
"updatedAt": "2026-08-13",
|
||||
"integrations": [
|
||||
{
|
||||
"type": "onepassword",
|
||||
@@ -12045,6 +12045,49 @@
|
||||
"integrationType": "observability",
|
||||
"tags": ["monitoring", "error-tracking", "incident-management"]
|
||||
},
|
||||
{
|
||||
"type": "logrocket",
|
||||
"slug": "logrocket",
|
||||
"name": "LogRocket",
|
||||
"description": "Summarize sessions, manage users, and tag releases in LogRocket",
|
||||
"longDescription": "Integrate LogRocket into your workflow to request AI session highlights for a user, poll for the result, list exported session files, read the audit log, create or update user profiles, and register releases so source maps decode their stack traces.",
|
||||
"bgColor": "#764ABC",
|
||||
"iconName": "LogRocketIcon",
|
||||
"docsUrl": "https://docs.sim.ai/integrations/logrocket",
|
||||
"operations": [
|
||||
{
|
||||
"name": "Request Highlights",
|
||||
"description": "Start a Galileo session highlights job for a user. Returns a request ID to poll with LogRocket's Get Highlights operation."
|
||||
},
|
||||
{
|
||||
"name": "Get Highlights",
|
||||
"description": "Retrieve the result of a Galileo session highlights request. Status is PENDING until generation finishes, then READY or FAILED."
|
||||
},
|
||||
{
|
||||
"name": "List Exported Sessions",
|
||||
"description": "List exported session files from the LogRocket Data Export API. Returns download URLs for JSON Lines exports, oldest first, plus a cursor for the next page."
|
||||
},
|
||||
{
|
||||
"name": "Get Audit Logs",
|
||||
"description": "Export audit log entries from LogRocket, recording who viewed sessions and what actions were taken. Paginated with a cursor."
|
||||
},
|
||||
{
|
||||
"name": "Identify User",
|
||||
"description": "Create or update a LogRocket user profile with demographic, financial, and engagement traits."
|
||||
},
|
||||
{
|
||||
"name": "Create Release",
|
||||
"description": "Register a release version in LogRocket so uploaded source maps can decode stack traces for it. Fails with a conflict if the version already exists."
|
||||
}
|
||||
],
|
||||
"operationCount": 6,
|
||||
"triggers": [],
|
||||
"triggerCount": 0,
|
||||
"authType": "api-key",
|
||||
"category": "tools",
|
||||
"integrationType": "observability",
|
||||
"tags": ["monitoring", "error-tracking", "data-analytics"]
|
||||
},
|
||||
{
|
||||
"type": "loops",
|
||||
"slug": "loops",
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,96 @@
|
||||
import type {
|
||||
LogRocketCreateReleaseParams,
|
||||
LogRocketCreateReleaseResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
/**
|
||||
* Registers a release so LogRocket can match uploaded source maps to it.
|
||||
*
|
||||
* This endpoint is not covered by the prose docs; its path, body, and 409
|
||||
* duplicate semantics come from LogRocket's own open-source CLI, which calls it
|
||||
* for `logrocket release <version>`.
|
||||
* See https://github.com/LogRocket/logrocket-cli (`src/apiClient.js`,
|
||||
* `src/commands/release.js`). The CLI never reads the response body, so this
|
||||
* tool reports only what the status line proves rather than inventing fields.
|
||||
*/
|
||||
export const createReleaseTool: ToolConfig<
|
||||
LogRocketCreateReleaseParams,
|
||||
LogRocketCreateReleaseResponse
|
||||
> = {
|
||||
id: 'logrocket_create_release',
|
||||
name: 'LogRocket Create Release',
|
||||
description:
|
||||
'Register a release version in LogRocket so uploaded source maps can decode stack traces for it. Fails with a conflict if the version already exists.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
version: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Release version to register, e.g. 1.2.3 or a commit SHA',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => buildAppUrl(params, 'releases/').toString(),
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
...buildAuthHeaders(params.apiKey),
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({ version: params.version.trim() }),
|
||||
},
|
||||
|
||||
/**
|
||||
* The executor rejects any non-2xx before this runs, so a duplicate version
|
||||
* (HTTP 409) surfaces as a tool error rather than a quiet no-op, and reaching
|
||||
* here means the release was registered. Only the echoed version is reported —
|
||||
* the CLI never reads the response body, so its shape is unverified and
|
||||
* nothing is invented here.
|
||||
*/
|
||||
transformResponse: async (response: Response, params) => {
|
||||
await throwOnError(response, 'LogRocket Releases API')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
version: params?.version?.trim() ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
version: {
|
||||
type: 'string',
|
||||
description: 'Release version that was registered',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import type {
|
||||
LogRocketGetAuditLogsParams,
|
||||
LogRocketGetAuditLogsResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const getAuditLogsTool: ToolConfig<
|
||||
LogRocketGetAuditLogsParams,
|
||||
LogRocketGetAuditLogsResponse
|
||||
> = {
|
||||
id: 'logrocket_get_audit_logs',
|
||||
name: 'LogRocket Get Audit Logs',
|
||||
description:
|
||||
'Export audit log entries from LogRocket, recording who viewed sessions and what actions were taken. Paginated with a cursor.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of audit log records to return',
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor from a previous page, used to fetch the next page',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = buildAppUrl(params, 'audit/logs/')
|
||||
if (params.limit) url.searchParams.set('limit', params.limit.trim())
|
||||
if (params.cursor) url.searchParams.set('cursor', params.cursor.trim())
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => buildAuthHeaders(params.apiKey),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = (await throwOnError(response, 'LogRocket Audit Log API')) as {
|
||||
has_next?: boolean
|
||||
cursor?: string | number
|
||||
logs?: Array<{
|
||||
time?: string
|
||||
created_date?: string
|
||||
user?: string
|
||||
action?: string
|
||||
description?: string
|
||||
}>
|
||||
} | null
|
||||
|
||||
const logs = (data?.logs ?? []).map((log) => ({
|
||||
time: log.time ?? null,
|
||||
createdDate: log.created_date ?? null,
|
||||
user: log.user ?? null,
|
||||
action: log.action ?? null,
|
||||
description: log.description ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
logs,
|
||||
cursor: data?.cursor === undefined || data.cursor === null ? null : String(data.cursor),
|
||||
hasNext: data?.has_next ?? false,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
logs: {
|
||||
type: 'array',
|
||||
description: 'Audit log entries',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
time: { type: 'string', description: 'Formatted timestamp of the action' },
|
||||
createdDate: { type: 'string', description: 'ISO 8601 timestamp of the action' },
|
||||
user: { type: 'string', description: 'Email or system ID of the actor' },
|
||||
action: { type: 'string', description: 'Action taken, e.g. Viewed session' },
|
||||
description: { type: 'string', description: 'Action details, e.g. the session ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
description: 'Opaque cursor for the next page of results',
|
||||
optional: true,
|
||||
},
|
||||
hasNext: {
|
||||
type: 'boolean',
|
||||
description: 'Whether more audit logs exist beyond this page',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
import type {
|
||||
LogRocketGetHighlightsParams,
|
||||
LogRocketGetHighlightsResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const getHighlightsTool: ToolConfig<
|
||||
LogRocketGetHighlightsParams,
|
||||
LogRocketGetHighlightsResponse
|
||||
> = {
|
||||
id: 'logrocket_get_highlights',
|
||||
name: 'LogRocket Get Highlights',
|
||||
description:
|
||||
'Retrieve the result of a Galileo session highlights request. Status is PENDING until generation finishes, then READY or FAILED.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Request ID returned by the Request Highlights operation',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = buildAppUrl(params, 'highlights')
|
||||
url.searchParams.set('id', params.id.trim())
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => buildAuthHeaders(params.apiKey),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = (await throwOnError(response, 'LogRocket Highlights API')) as {
|
||||
status?: string
|
||||
requestID?: string
|
||||
appID?: string
|
||||
result?: {
|
||||
highlights?: string
|
||||
sessions?: Array<{ recordingID?: string; sessionID?: number; highlights?: string }>
|
||||
} | null
|
||||
} | null
|
||||
|
||||
const sessions = (data?.result?.sessions ?? []).map((session) => ({
|
||||
recordingID: session.recordingID ?? null,
|
||||
sessionID: session.sessionID ?? null,
|
||||
highlights: session.highlights ?? null,
|
||||
}))
|
||||
|
||||
if (!data?.status) {
|
||||
throw new Error('LogRocket Highlights API did not return a job status')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
status: data.status,
|
||||
requestID: data?.requestID ?? null,
|
||||
appID: data?.appID ?? null,
|
||||
highlights: data?.result?.highlights ?? null,
|
||||
sessions,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Job status: PENDING, READY, or FAILED',
|
||||
},
|
||||
requestID: {
|
||||
type: 'string',
|
||||
description: 'ID of the highlights request',
|
||||
optional: true,
|
||||
},
|
||||
appID: {
|
||||
type: 'string',
|
||||
description: 'LogRocket project the request belongs to',
|
||||
optional: true,
|
||||
},
|
||||
highlights: {
|
||||
type: 'string',
|
||||
description: 'Markdown summary across the matched sessions. Present when status is READY.',
|
||||
optional: true,
|
||||
},
|
||||
sessions: {
|
||||
type: 'array',
|
||||
description: 'Per-session highlights',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
recordingID: { type: 'string', description: 'LogRocket recording ID' },
|
||||
sessionID: { type: 'number', description: 'Session number within the recording' },
|
||||
highlights: { type: 'string', description: 'Highlights for this session' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
import type {
|
||||
LogRocketIdentifyUserParams,
|
||||
LogRocketIdentifyUserResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const identifyUserTool: ToolConfig<
|
||||
LogRocketIdentifyUserParams,
|
||||
LogRocketIdentifyUserResponse
|
||||
> = {
|
||||
id: 'logrocket_identify_user',
|
||||
name: 'LogRocket Identify User',
|
||||
description:
|
||||
'Create or update a LogRocket user profile with demographic, financial, and engagement traits.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the user to create or update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Display name of the user. Maximum 1024 characters.',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email of the user. Maximum 1024 characters.',
|
||||
},
|
||||
timestamp: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Unix timestamp in milliseconds describing when the submitted data was true',
|
||||
},
|
||||
traits: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON object of custom traits. Each key and value is limited to 1024 characters and stored as a string.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
buildAppUrl(params, `users/${encodeURIComponent(params.userId.trim())}`).toString(),
|
||||
method: 'PUT',
|
||||
headers: (params) => ({
|
||||
...buildAuthHeaders(params.apiKey),
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
|
||||
const name = params.name?.trim()
|
||||
const email = params.email?.trim()
|
||||
|
||||
if (name) body.name = name
|
||||
if (email) body.email = email
|
||||
|
||||
if (params.timestamp?.trim()) {
|
||||
const timestamp = Number(params.timestamp)
|
||||
if (!Number.isFinite(timestamp)) {
|
||||
throw new Error('LogRocket Identify User: timestamp must be milliseconds since epoch')
|
||||
}
|
||||
body.timestamp = timestamp
|
||||
}
|
||||
|
||||
if (params.traits?.trim()) {
|
||||
let parsed: unknown
|
||||
try {
|
||||
parsed = JSON.parse(params.traits)
|
||||
} catch {
|
||||
throw new Error('LogRocket Identify User: traits must be a valid JSON object')
|
||||
}
|
||||
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
||||
throw new Error(
|
||||
'LogRocket Identify User: traits must be a JSON object, not an array or scalar'
|
||||
)
|
||||
}
|
||||
body.traits = parsed
|
||||
}
|
||||
|
||||
if (Object.keys(body).length === 0) {
|
||||
throw new Error(
|
||||
'LogRocket Identify User: provide at least one of name, email, timestamp, or traits'
|
||||
)
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = (await throwOnError(response, 'LogRocket User Identification API')) as {
|
||||
userID?: string
|
||||
name?: string
|
||||
email?: string
|
||||
traits?: Record<string, string>
|
||||
} | null
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
userID: data?.userID ?? null,
|
||||
name: data?.name ?? null,
|
||||
email: data?.email ?? null,
|
||||
traits: data?.traits ?? {},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
userID: {
|
||||
type: 'string',
|
||||
description: 'ID of the created or updated user',
|
||||
optional: true,
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Display name stored on the profile',
|
||||
optional: true,
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
description: 'Email stored on the profile',
|
||||
optional: true,
|
||||
},
|
||||
traits: {
|
||||
type: 'json',
|
||||
description: 'Custom traits stored on the profile, with every value coerced to a string',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { createReleaseTool } from '@/tools/logrocket/create_release'
|
||||
import { getAuditLogsTool } from '@/tools/logrocket/get_audit_logs'
|
||||
import { getHighlightsTool } from '@/tools/logrocket/get_highlights'
|
||||
import { identifyUserTool } from '@/tools/logrocket/identify_user'
|
||||
import { listExportedSessionsTool } from '@/tools/logrocket/list_exported_sessions'
|
||||
import { requestHighlightsTool } from '@/tools/logrocket/request_highlights'
|
||||
|
||||
export const logrocketRequestHighlightsTool = requestHighlightsTool
|
||||
export const logrocketGetHighlightsTool = getHighlightsTool
|
||||
export const logrocketListExportedSessionsTool = listExportedSessionsTool
|
||||
export const logrocketGetAuditLogsTool = getAuditLogsTool
|
||||
export const logrocketIdentifyUserTool = identifyUserTool
|
||||
export const logrocketCreateReleaseTool = createReleaseTool
|
||||
@@ -0,0 +1,111 @@
|
||||
import type {
|
||||
LogRocketListExportedSessionsParams,
|
||||
LogRocketListExportedSessionsResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listExportedSessionsTool: ToolConfig<
|
||||
LogRocketListExportedSessionsParams,
|
||||
LogRocketListExportedSessionsResponse
|
||||
> = {
|
||||
id: 'logrocket_list_exported_sessions',
|
||||
name: 'LogRocket List Exported Sessions',
|
||||
description:
|
||||
'List exported session files from the LogRocket Data Export API. Returns download URLs for JSON Lines exports, oldest first, plus a cursor for the next page.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor from a previous page, used to fetch newer sessions',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page. Defaults to 10, maximum 100.',
|
||||
},
|
||||
date: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Unix timestamp in milliseconds to start listing from',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = buildAppUrl(params, 'data-export/')
|
||||
if (params.cursor) url.searchParams.set('cursor', params.cursor.trim())
|
||||
if (params.limit) url.searchParams.set('limit', params.limit.trim())
|
||||
if (params.date) url.searchParams.set('date', params.date.trim())
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => buildAuthHeaders(params.apiKey),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = (await throwOnError(response, 'LogRocket Data Export API')) as {
|
||||
cursor?: string | number
|
||||
sessions?: Array<{ url?: string }>
|
||||
} | null
|
||||
|
||||
const sessions = (data?.sessions ?? []).map((session) => ({
|
||||
url: session.url ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
sessions,
|
||||
cursor: data?.cursor === undefined || data.cursor === null ? null : String(data.cursor),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
sessions: {
|
||||
type: 'array',
|
||||
description: 'Exported session files',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string', description: 'Download URL for the JSON Lines export file' },
|
||||
},
|
||||
},
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
description: 'Opaque cursor for the next page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import type {
|
||||
LogRocketRequestHighlightsParams,
|
||||
LogRocketRequestHighlightsResponse,
|
||||
} from '@/tools/logrocket/types'
|
||||
import { buildAppUrl, buildAuthHeaders, throwOnError } from '@/tools/logrocket/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const requestHighlightsTool: ToolConfig<
|
||||
LogRocketRequestHighlightsParams,
|
||||
LogRocketRequestHighlightsResponse
|
||||
> = {
|
||||
id: 'logrocket_request_highlights',
|
||||
name: 'LogRocket Request Highlights',
|
||||
description:
|
||||
"Start a Galileo session highlights job for a user. Returns a request ID to poll with LogRocket's Get Highlights operation.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket API key',
|
||||
},
|
||||
orgId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket organization ID',
|
||||
},
|
||||
appId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'LogRocket project (app) ID',
|
||||
},
|
||||
apiHost: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'API host override for Private Cloud deployments',
|
||||
},
|
||||
userEmail: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email of the user to summarize. Required if no user ID is given.',
|
||||
},
|
||||
userID: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the user to summarize. Required if no email is given.',
|
||||
},
|
||||
question: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Question to focus the highlights on',
|
||||
},
|
||||
startMs: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start of the session window, in milliseconds since epoch',
|
||||
},
|
||||
endMs: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End of the session window, in milliseconds since epoch',
|
||||
},
|
||||
webhookURL: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'URL notified when the highlights job finishes',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
/**
|
||||
* Galileo Highlights answers `question` with an LLM, so that string is the
|
||||
* only model-visible field here. The identity, time-window, and webhook
|
||||
* fields are lookup and control inputs that never reach the model.
|
||||
*/
|
||||
modelInput: {
|
||||
mode: 'project',
|
||||
select: (params) => (params.question?.trim() ? { question: params.question } : {}),
|
||||
},
|
||||
url: (params) => buildAppUrl(params, 'highlights/').toString(),
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
...buildAuthHeaders(params.apiKey),
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
|
||||
/*
|
||||
* Trim before testing presence: a whitespace-only value from an upstream
|
||||
* block is not an identity, and forwarding it would have LogRocket reject
|
||||
* the request instead of failing here with a usable message.
|
||||
*/
|
||||
const userEmail = params.userEmail?.trim()
|
||||
const userID = params.userID?.trim()
|
||||
const question = params.question?.trim()
|
||||
const webhookURL = params.webhookURL?.trim()
|
||||
|
||||
if (!userEmail && !userID) {
|
||||
throw new Error(
|
||||
'LogRocket Request Highlights: provide either a user email or a user ID to summarize'
|
||||
)
|
||||
}
|
||||
|
||||
if (userEmail) body.userEmail = userEmail
|
||||
if (userID) body.userID = userID
|
||||
if (question) body.question = question
|
||||
if (webhookURL) body.webhookURL = webhookURL
|
||||
|
||||
/*
|
||||
* The API requires both bounds whenever timeRange is present, so a partial
|
||||
* or non-numeric window fails loudly rather than silently widening the
|
||||
* search to the user's entire session history.
|
||||
*/
|
||||
const hasStart = Boolean(params.startMs?.trim())
|
||||
const hasEnd = Boolean(params.endMs?.trim())
|
||||
if (hasStart !== hasEnd) {
|
||||
throw new Error('LogRocket Request Highlights: startMs and endMs must be provided together')
|
||||
}
|
||||
if (hasStart && hasEnd) {
|
||||
const startMs = Number(params.startMs)
|
||||
const endMs = Number(params.endMs)
|
||||
if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) {
|
||||
throw new Error(
|
||||
'LogRocket Request Highlights: startMs and endMs must be milliseconds since epoch'
|
||||
)
|
||||
}
|
||||
if (startMs >= endMs) {
|
||||
throw new Error('LogRocket Request Highlights: startMs must be earlier than endMs')
|
||||
}
|
||||
body.timeRange = { startMs, endMs }
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = (await throwOnError(response, 'LogRocket Highlights API')) as {
|
||||
id?: string
|
||||
} | null
|
||||
|
||||
if (!data?.id) {
|
||||
throw new Error('LogRocket Highlights API did not return a request ID')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Request ID used to retrieve the highlights result',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
/**
|
||||
* Every LogRocket REST endpoint is scoped to an organization and an application
|
||||
* (called the "project id" in the dashboard), and authenticates with an API key
|
||||
* sent as `Authorization: token <key>`.
|
||||
*/
|
||||
interface LogRocketBaseParams {
|
||||
apiKey: string
|
||||
orgId: string
|
||||
appId: string
|
||||
/** Override for Private Cloud deployments. Defaults to https://api.logrocket.com. */
|
||||
apiHost?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Galileo session highlights for a user (Session Highlights API).
|
||||
*/
|
||||
export interface LogRocketRequestHighlightsParams extends LogRocketBaseParams {
|
||||
userEmail?: string
|
||||
userID?: string
|
||||
question?: string
|
||||
/** Start of the session window, in milliseconds since epoch. */
|
||||
startMs?: string
|
||||
/** End of the session window, in milliseconds since epoch. */
|
||||
endMs?: string
|
||||
webhookURL?: string
|
||||
}
|
||||
|
||||
export interface LogRocketRequestHighlightsResponse extends ToolResponse {
|
||||
output: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result of a previously requested highlights job.
|
||||
*/
|
||||
export interface LogRocketGetHighlightsParams extends LogRocketBaseParams {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface LogRocketGetHighlightsResponse extends ToolResponse {
|
||||
output: {
|
||||
/** PENDING, READY, or FAILED. */
|
||||
status: string
|
||||
requestID: string | null
|
||||
appID: string | null
|
||||
/** Markdown summary across all sessions. Present only when status is READY. */
|
||||
highlights: string | null
|
||||
sessions: Array<{
|
||||
recordingID: string | null
|
||||
sessionID: number | null
|
||||
highlights: string | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List exported session files (Data Export API).
|
||||
*/
|
||||
export interface LogRocketListExportedSessionsParams extends LogRocketBaseParams {
|
||||
cursor?: string
|
||||
limit?: string
|
||||
/** Unix timestamp in milliseconds to start listing from. */
|
||||
date?: string
|
||||
}
|
||||
|
||||
export interface LogRocketListExportedSessionsResponse extends ToolResponse {
|
||||
output: {
|
||||
sessions: Array<{ url: string | null }>
|
||||
cursor: string | null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the organization audit log (Audit Log API).
|
||||
*/
|
||||
export interface LogRocketGetAuditLogsParams extends LogRocketBaseParams {
|
||||
limit?: string
|
||||
cursor?: string
|
||||
}
|
||||
|
||||
export interface LogRocketGetAuditLogsResponse extends ToolResponse {
|
||||
output: {
|
||||
logs: Array<{
|
||||
time: string | null
|
||||
createdDate: string | null
|
||||
user: string | null
|
||||
action: string | null
|
||||
description: string | null
|
||||
}>
|
||||
cursor: string | null
|
||||
hasNext: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a release so uploaded source maps can decode its stack traces.
|
||||
*/
|
||||
export interface LogRocketCreateReleaseParams extends LogRocketBaseParams {
|
||||
version: string
|
||||
}
|
||||
|
||||
export interface LogRocketCreateReleaseResponse extends ToolResponse {
|
||||
output: {
|
||||
version: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a user profile (User Identification API).
|
||||
*/
|
||||
export interface LogRocketIdentifyUserParams extends LogRocketBaseParams {
|
||||
userId: string
|
||||
name?: string
|
||||
email?: string
|
||||
/** Unix timestamp in milliseconds describing when the submitted data was true. */
|
||||
timestamp?: string
|
||||
/** JSON object of custom traits. Each value is stored as a string. */
|
||||
traits?: string
|
||||
}
|
||||
|
||||
export interface LogRocketIdentifyUserResponse extends ToolResponse {
|
||||
output: {
|
||||
userID: string | null
|
||||
name: string | null
|
||||
email: string | null
|
||||
traits: Record<string, string>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
const DEFAULT_API_HOST = 'https://api.logrocket.com'
|
||||
|
||||
interface AppScope {
|
||||
orgId: string
|
||||
appId: string
|
||||
apiHost?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Every LogRocket REST endpoint hangs off `/v1/orgs/<org>/apps/<app>/`. Private
|
||||
* Cloud deployments serve the same paths from their own `domains.api` host.
|
||||
* See https://docs.logrocket.com/docs/data-export
|
||||
*/
|
||||
export function buildAppUrl(params: AppScope, path: string): URL {
|
||||
const host = (params.apiHost || DEFAULT_API_HOST).trim().replace(/\/+$/, '')
|
||||
const org = encodeURIComponent(params.orgId.trim())
|
||||
const app = encodeURIComponent(params.appId.trim())
|
||||
return new URL(`${host}/v1/orgs/${org}/apps/${app}/${path}`)
|
||||
}
|
||||
|
||||
export function buildAuthHeaders(apiKey: string): Record<string, string> {
|
||||
return { Authorization: `token ${apiKey}` }
|
||||
}
|
||||
|
||||
/**
|
||||
* LogRocket returns plain text for some error statuses, so the JSON parse is
|
||||
* best-effort and the raw body is preserved as the fallback message.
|
||||
*/
|
||||
export async function throwOnError(response: Response, label: string): Promise<unknown> {
|
||||
const text = await response.text()
|
||||
let data: unknown = null
|
||||
try {
|
||||
data = text ? JSON.parse(text) : null
|
||||
} catch {
|
||||
data = null
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(data as { error?: string; message?: string } | null)?.error ??
|
||||
(data as { error?: string; message?: string } | null)?.message ??
|
||||
text
|
||||
throw new Error(`${label} error (${response.status}): ${message || response.statusText}`)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import { googleTranslateTool } from '@/tools/google_translate/text'
|
||||
import { queryTool as greptileQueryTool } from '@/tools/greptile/query'
|
||||
import { discoverTool as hunterDiscoverTool } from '@/tools/hunter/discover'
|
||||
import { searchTool as linkupSearchTool } from '@/tools/linkup/search'
|
||||
import { requestHighlightsTool as logrocketRequestHighlightsTool } from '@/tools/logrocket/request_highlights'
|
||||
import { mem0SearchMemoriesTool } from '@/tools/mem0/search_memories'
|
||||
import { deepResearchTool as parallelDeepResearchTool } from '@/tools/parallel/deep_research'
|
||||
import { searchTextTool as pineconeSearchTextTool } from '@/tools/pinecone/search_text'
|
||||
@@ -345,6 +346,22 @@ describe('model-facing integration selectors', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('projects only the LogRocket Galileo question, never the session lookup or control fields', () => {
|
||||
expect(
|
||||
selectModelInput(logrocketRequestHighlightsTool, {
|
||||
question: 'why did checkout fail',
|
||||
userEmail: 'user@example.com',
|
||||
userID: 'user-1',
|
||||
startMs: '1700000000000',
|
||||
endMs: '1700003600000',
|
||||
webhookURL: 'https://example.com/hook',
|
||||
})
|
||||
).toStrictEqual({ question: 'why did checkout fail' })
|
||||
expect(
|
||||
selectModelInput(logrocketRequestHighlightsTool, { userEmail: 'user@example.com' })
|
||||
).toStrictEqual({})
|
||||
})
|
||||
|
||||
it('projects Tavily and Context.dev natural-language crawl or fanout instructions', () => {
|
||||
expect(selectModelInput(tavilyCrawlTool, { instructions: 'find pricing' })).toStrictEqual({
|
||||
instructions: 'find pricing',
|
||||
|
||||
@@ -2449,6 +2449,14 @@ import {
|
||||
logfireQueryTool,
|
||||
logfireSearchRecordsTool,
|
||||
} from '@/tools/logfire'
|
||||
import {
|
||||
logrocketCreateReleaseTool,
|
||||
logrocketGetAuditLogsTool,
|
||||
logrocketGetHighlightsTool,
|
||||
logrocketIdentifyUserTool,
|
||||
logrocketListExportedSessionsTool,
|
||||
logrocketRequestHighlightsTool,
|
||||
} from '@/tools/logrocket'
|
||||
import {
|
||||
logsGetExecutionTool,
|
||||
logsGetRunDetailsTool,
|
||||
@@ -5420,6 +5428,12 @@ export const tools: Record<string, ToolConfig> = {
|
||||
logfire_get_trace: logfireGetTraceTool,
|
||||
logfire_query: logfireQueryTool,
|
||||
logfire_search_records: logfireSearchRecordsTool,
|
||||
logrocket_create_release: logrocketCreateReleaseTool,
|
||||
logrocket_get_audit_logs: logrocketGetAuditLogsTool,
|
||||
logrocket_get_highlights: logrocketGetHighlightsTool,
|
||||
logrocket_identify_user: logrocketIdentifyUserTool,
|
||||
logrocket_list_exported_sessions: logrocketListExportedSessionsTool,
|
||||
logrocket_request_highlights: logrocketRequestHighlightsTool,
|
||||
logs_query: logsQueryTool,
|
||||
logs_query_runs: logsQueryRunsTool,
|
||||
logs_get: logsGetTool,
|
||||
|
||||
Reference in New Issue
Block a user