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:
Waleed
2026-08-13 15:01:22 -07:00
committed by GitHub
parent c155a57c76
commit 58b5ee9337
23 changed files with 1837 additions and 11 deletions
+18 -1
View File
@@ -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
+4 -3
View File
@@ -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",
+534
View File
@@ -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
+3
View File
@@ -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,
+17
View File
@@ -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
+4 -3
View File
@@ -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,
+44 -1
View File
@@ -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',
},
},
}
+124
View File
@@ -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',
},
},
}
+127
View File
@@ -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' },
},
},
},
},
}
+166
View File
@@ -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',
},
},
}
+13
View File
@@ -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',
},
},
}
+131
View File
@@ -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>
}
}
+47
View File
@@ -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',
+14
View File
@@ -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,