Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 192 additions & 23 deletions apps/sim/blocks/blocks/posthog.ts

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions apps/sim/tools/error-extractors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@ const ERROR_EXTRACTORS: ErrorExtractorConfig[] = [
return undefined
},
},
{
id: 'posthog-errors',
description: 'PostHog API error format with type/code/detail/attr fields',
examples: ['PostHog API'],
extract: (errorInfo) => {
const detail = errorInfo?.data?.detail
if (typeof detail !== 'string' || !detail.trim()) return undefined
const attr = errorInfo?.data?.attr
return typeof attr === 'string' && attr ? `${detail} (${attr})` : detail
},
},
{
id: 'plain-text-data',
description: 'Plain text error response',
Expand Down Expand Up @@ -320,6 +331,7 @@ export const ErrorExtractorId = {
SOAP_FAULT: 'soap-fault',
OAUTH_ERROR_DESCRIPTION: 'oauth-error-description',
NESTED_ERROR_OBJECT: 'nested-error-object',
POSTHOG_ERRORS: 'posthog-errors',
PLAIN_TEXT_DATA: 'plain-text-data',
HTTP_STATUS_TEXT: 'http-status-text',
} as const
49 changes: 27 additions & 22 deletions apps/sim/tools/posthog/batch_events.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogIngestBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'

export interface PostHogBatchEventsParams {
projectApiKey: string
region?: 'us' | 'eu'
host?: string
batch: string
}

Expand Down Expand Up @@ -35,6 +38,13 @@ export const batchEventsTool: ToolConfig<PostHogBatchEventsParams, PostHogBatchE
description: 'PostHog region: us (default) or eu',
default: 'us',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Self-hosted PostHog instance host (e.g., "posthog.mycompany.com"). Overrides the region setting when provided.',
},
batch: {
type: 'string',
required: true,
Expand All @@ -46,49 +56,44 @@ export const batchEventsTool: ToolConfig<PostHogBatchEventsParams, PostHogBatchE

request: {
url: (params) => {
const baseUrl =
params.region === 'eu' ? 'https://eu.i.posthog.com' : 'https://us.i.posthog.com'
const baseUrl = getPostHogIngestBaseUrl(params.region, params.host)
return `${baseUrl}/batch/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
}),
body: (params) => {
let batch: any[]
let batch: unknown
try {
batch = JSON.parse(params.batch)
} catch (e) {
batch = []
} catch (error) {
throw new Error(`Invalid batch JSON: ${getErrorMessage(error)}`)
}
if (!Array.isArray(batch)) {
throw new Error('batch must be a JSON array of events')
}

return {
api_key: params.projectApiKey,
batch: batch,
batch,
}
},
},

transformResponse: async (response: Response) => {
if (response.ok) {
const data = await response.json()
return {
success: true,
output: {
status: 'Batch events captured successfully',
events_processed: data.status === 1 ? JSON.parse(data.batch || '[]').length : 0,
},
}
}
transformResponse: async (response: Response, params) => {
const data = await response.json()
const eventsProcessed = params ? (JSON.parse(params.batch) as unknown[]).length : 0
const success = data.status === 1

const error = await response.text()
return {
success: false,
success,
output: {
status: 'Failed to capture batch events',
events_processed: 0,
status: success
? 'Batch events captured successfully'
: `Batch events capture failed (status: ${data.status})`,
events_processed: success ? eventsProcessed : 0,
},
error: error || 'Unknown error occurred',
}
},

Expand Down
35 changes: 19 additions & 16 deletions apps/sim/tools/posthog/capture_event.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogIngestBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'

export interface PostHogCaptureEventParams {
projectApiKey: string
region?: 'us' | 'eu'
host?: string
event: string
distinctId: string
properties?: string
Expand Down Expand Up @@ -38,6 +41,13 @@ export const captureEventTool: ToolConfig<PostHogCaptureEventParams, PostHogCapt
description: 'PostHog region: us (default) or eu',
default: 'us',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Self-hosted PostHog instance host (e.g., "posthog.mycompany.com"). Overrides the region setting when provided.',
},
event: {
type: 'string',
required: true,
Expand Down Expand Up @@ -69,8 +79,7 @@ export const captureEventTool: ToolConfig<PostHogCaptureEventParams, PostHogCapt

request: {
url: (params) => {
const baseUrl =
params.region === 'eu' ? 'https://eu.i.posthog.com' : 'https://us.i.posthog.com'
const baseUrl = getPostHogIngestBaseUrl(params.region, params.host)
return `${baseUrl}/capture/`
},
method: 'POST',
Expand All @@ -87,8 +96,8 @@ export const captureEventTool: ToolConfig<PostHogCaptureEventParams, PostHogCapt
if (params.properties) {
try {
body.properties = JSON.parse(params.properties)
} catch (e) {
body.properties = {}
} catch (error) {
throw new Error(`Invalid properties JSON: ${getErrorMessage(error)}`)
}
}

Expand All @@ -101,22 +110,16 @@ export const captureEventTool: ToolConfig<PostHogCaptureEventParams, PostHogCapt
},

transformResponse: async (response: Response) => {
if (response.ok) {
return {
success: true,
output: {
status: 'Event captured successfully',
},
}
}
const data = await response.json()
const success = data.status === 1

const error = await response.text()
return {
success: false,
success,
output: {
status: 'Failed to capture event',
Comment thread
waleedlatif1 marked this conversation as resolved.
status: success
? 'Event captured successfully'
: `Event capture failed (status: ${data.status})`,
},
error: error || 'Unknown error occurred',
}
},

Expand Down
38 changes: 29 additions & 9 deletions apps/sim/tools/posthog/create_annotation.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'

interface PostHogCreateAnnotationParams {
apiKey: string
projectId: string
region: string
host?: string
content: string
date_marker: string
scope?: string
dashboard_item?: string
insight_short_id?: string
dashboard_id?: string
}

interface PostHogCreateAnnotationResponse {
Expand All @@ -21,6 +23,7 @@ interface PostHogCreateAnnotationResponse {
updated_at: string
created_by: Record<string, any> | null
dashboard_item: number | null
dashboard_id: number | null
insight_short_id: string | null
insight_name: string | null
scope: string
Expand All @@ -37,6 +40,7 @@ export const createAnnotationTool: ToolConfig<
description:
'Create a new annotation in PostHog. Mark important events on your graphs with date and description.',
version: '1.0.0',
errorExtractor: 'posthog-errors',

params: {
apiKey: {
Expand All @@ -58,6 +62,13 @@ export const createAnnotationTool: ToolConfig<
description: 'PostHog cloud region: "us" or "eu" (default: "us")',
default: 'us',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Self-hosted PostHog instance host (e.g., "posthog.mycompany.com"). Overrides the region setting when provided.',
},
content: {
type: 'string',
required: true,
Expand All @@ -75,25 +86,28 @@ export const createAnnotationTool: ToolConfig<
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Scope of the annotation: "project" or "dashboard_item" (default: "project")',
description:
'Scope of the annotation: "project", "organization", "dashboard", or "dashboard_item" (default: "project")',
},
dashboard_item: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of dashboard item to attach this annotation to',
description:
'ID of the dashboard tile (insight) to attach this annotation to (used when scope is "dashboard_item")',
},
insight_short_id: {
dashboard_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Short ID of the insight to attach this annotation to',
description:
'ID of the dashboard to attach this annotation to (used when scope is "dashboard")',
},
},

request: {
url: (params) => {
const baseUrl = params.region === 'eu' ? 'https://eu.posthog.com' : 'https://us.posthog.com'
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/annotations/`
},
method: 'POST',
Expand All @@ -115,8 +129,8 @@ export const createAnnotationTool: ToolConfig<
body.dashboard_item = Number(params.dashboard_item)
}

if (params.insight_short_id) {
body.insight_short_id = params.insight_short_id
if (params.dashboard_id) {
body.dashboard_id = Number(params.dashboard_id)
}

return body
Expand All @@ -136,6 +150,7 @@ export const createAnnotationTool: ToolConfig<
updated_at: data.updated_at,
created_by: data.created_by || null,
dashboard_item: data.dashboard_item || null,
dashboard_id: data.dashboard_id || null,
insight_short_id: data.insight_short_id || null,
insight_name: data.insight_name || null,
scope: data.scope || '',
Expand Down Expand Up @@ -175,6 +190,11 @@ export const createAnnotationTool: ToolConfig<
description: 'ID of dashboard item this annotation is attached to',
optional: true,
},
dashboard_id: {
type: 'number',
description: 'ID of the dashboard this annotation is attached to',
optional: true,
},
insight_short_id: {
type: 'string',
description: 'Short ID of the insight this annotation is attached to',
Expand All @@ -187,7 +207,7 @@ export const createAnnotationTool: ToolConfig<
},
scope: {
type: 'string',
description: 'Scope of the annotation (project or dashboard_item)',
description: 'Scope of the annotation (project, organization, dashboard, or dashboard_item)',
},
deleted: {
type: 'boolean',
Expand Down
12 changes: 11 additions & 1 deletion apps/sim/tools/posthog/create_cohort.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'

interface PostHogCreateCohortParams {
apiKey: string
projectId: string
region: string
host?: string
name: string
description?: string
filters?: string
Expand Down Expand Up @@ -38,6 +40,7 @@ export const createCohortTool: ToolConfig<PostHogCreateCohortParams, PostHogCrea
description:
'Create a new cohort in PostHog. Requires cohort name and filter or query configuration.',
version: '1.0.0',
errorExtractor: 'posthog-errors',

params: {
apiKey: {
Expand All @@ -59,6 +62,13 @@ export const createCohortTool: ToolConfig<PostHogCreateCohortParams, PostHogCrea
description: 'PostHog cloud region: "us" or "eu" (default: "us")',
default: 'us',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Self-hosted PostHog instance host (e.g., "posthog.mycompany.com"). Overrides the region setting when provided.',
},
name: {
type: 'string',
required: false,
Expand Down Expand Up @@ -101,7 +111,7 @@ export const createCohortTool: ToolConfig<PostHogCreateCohortParams, PostHogCrea

request: {
url: (params) => {
const baseUrl = params.region === 'eu' ? 'https://eu.posthog.com' : 'https://us.posthog.com'
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/cohorts/`
},
method: 'POST',
Expand Down
Loading
Loading