chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
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
}
export interface PostHogBatchEventsResponse {
success: boolean
output: {
status: string
events_processed: number
}
}
export const batchEventsTool: ToolConfig<PostHogBatchEventsParams, PostHogBatchEventsResponse> = {
id: 'posthog_batch_events',
name: 'PostHog Batch Events',
description:
'Capture multiple events at once in PostHog. Use this for bulk event ingestion to improve performance.',
version: '1.0.0',
params: {
projectApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Project API Key (public token for event ingestion)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description:
'JSON array of events to capture. Each event should have: event, distinct_id, and optional properties, timestamp. Example: [{"event": "page_view", "distinct_id": "user123", "properties": {"page": "/"}}]',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogIngestBaseUrl(params.region, params.host)
return `${baseUrl}/batch/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
}),
body: (params) => {
let batch: unknown
try {
batch = JSON.parse(params.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,
}
},
},
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
return {
success,
output: {
status: success
? 'Batch events captured successfully'
: `Batch events capture failed (status: ${data.status})`,
events_processed: success ? eventsProcessed : 0,
},
}
},
outputs: {
status: {
type: 'string',
description: 'Status message indicating whether the batch was captured successfully',
},
events_processed: {
type: 'number',
description: 'Number of events processed in the batch',
},
},
}
+132
View File
@@ -0,0 +1,132 @@
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
timestamp?: string
}
export interface PostHogCaptureEventResponse {
success: boolean
output: {
status: string
}
}
export const captureEventTool: ToolConfig<PostHogCaptureEventParams, PostHogCaptureEventResponse> =
{
id: 'posthog_capture_event',
name: 'PostHog Capture Event',
description:
'Capture a single event in PostHog. Use this to track user actions, page views, or custom events.',
version: '1.0.0',
params: {
projectApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Project API Key (public token for event ingestion)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description: 'The name of the event to capture (e.g., "page_view", "button_clicked")',
},
distinctId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Unique identifier for the user or device (e.g., "user123", email, or device UUID)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'JSON string of event properties (e.g., {"button_name": "signup", "page": "homepage"})',
},
timestamp: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'ISO 8601 timestamp for when the event occurred. If not provided, uses current time',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogIngestBaseUrl(params.region, params.host)
return `${baseUrl}/capture/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
api_key: params.projectApiKey,
event: params.event,
distinct_id: params.distinctId,
}
if (params.properties) {
try {
body.properties = JSON.parse(params.properties)
} catch (error) {
throw new Error(`Invalid properties JSON: ${getErrorMessage(error)}`)
}
}
if (params.timestamp) {
body.timestamp = params.timestamp
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
const success = data.status === 1
return {
success,
output: {
status: success
? 'Event captured successfully'
: `Event capture failed (status: ${data.status})`,
},
}
},
outputs: {
status: {
type: 'string',
description: 'Status message indicating whether the event was captured successfully',
},
},
}
+217
View File
@@ -0,0 +1,217 @@
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
dashboard_id?: string
}
interface PostHogCreateAnnotationResponse {
success: boolean
output: {
id: number
content: string
date_marker: string
created_at: string
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
deleted: boolean
}
}
export const createAnnotationTool: ToolConfig<
PostHogCreateAnnotationParams,
PostHogCreateAnnotationResponse
> = {
id: 'posthog_create_annotation',
name: 'PostHog Create Annotation',
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: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description: 'Content/text of the annotation',
},
date_marker: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'ISO timestamp marking when the annotation applies (e.g., "2024-01-15T10:00:00Z")',
},
scope: {
type: 'string',
required: false,
visibility: 'user-or-llm',
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 the dashboard tile (insight) to attach this annotation to (used when scope is "dashboard_item")',
},
dashboard_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'ID of the dashboard to attach this annotation to (used when scope is "dashboard")',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/annotations/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {
content: params.content,
date_marker: params.date_marker,
}
if (params.scope) {
body.scope = params.scope
}
if (params.dashboard_item) {
body.dashboard_item = Number(params.dashboard_item)
}
if (params.dashboard_id) {
body.dashboard_id = Number(params.dashboard_id)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
content: data.content || '',
date_marker: data.date_marker,
created_at: data.created_at,
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 || '',
deleted: data.deleted || false,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the created annotation',
},
content: {
type: 'string',
description: 'Content/text of the annotation',
},
date_marker: {
type: 'string',
description: 'ISO timestamp marking when the annotation applies',
},
created_at: {
type: 'string',
description: 'ISO timestamp when annotation was created',
},
updated_at: {
type: 'string',
description: 'ISO timestamp when annotation was last updated',
},
created_by: {
type: 'object',
description: 'User who created the annotation',
optional: true,
},
dashboard_item: {
type: 'number',
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',
optional: true,
},
insight_name: {
type: 'string',
description: 'Name of the insight this annotation is attached to',
optional: true,
},
scope: {
type: 'string',
description: 'Scope of the annotation (project, organization, dashboard, or dashboard_item)',
},
deleted: {
type: 'boolean',
description: 'Whether the annotation is deleted',
},
},
}
+242
View File
@@ -0,0 +1,242 @@
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
query?: string
is_static?: boolean
groups?: string
}
interface PostHogCreateCohortResponse {
success: boolean
output: {
id: number
name: string
description: string
groups: Array<Record<string, any>>
deleted: boolean
filters: Record<string, any>
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
is_calculating: boolean
count: number
is_static: boolean
version: number
}
}
export const createCohortTool: ToolConfig<PostHogCreateCohortParams, PostHogCreateCohortResponse> =
{
id: 'posthog_create_cohort',
name: 'PostHog Create Cohort',
description:
'Create a new cohort in PostHog. Requires cohort name and filter or query configuration.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description:
'Name for the cohort (optional - PostHog will use "Untitled cohort" if not provided)',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the cohort',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of filter configuration for the cohort',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of query configuration for the cohort',
},
is_static: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the cohort is static (default: false)',
default: false,
},
groups: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of groups that define the cohort',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/cohorts/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
}
if (params.description) {
body.description = params.description
}
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (e) {
body.filters = {}
}
}
if (params.query) {
try {
body.query = JSON.parse(params.query)
} catch (e) {
body.query = null
}
}
if (params.is_static !== undefined) {
body.is_static = params.is_static
}
if (params.groups) {
try {
body.groups = JSON.parse(params.groups)
} catch (e) {
body.groups = []
}
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
groups: data.groups || [],
deleted: data.deleted || false,
filters: data.filters || {},
query: data.query || null,
created_at: data.created_at,
created_by: data.created_by || null,
is_calculating: data.is_calculating || false,
count: data.count || 0,
is_static: data.is_static || false,
version: data.version || 0,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the created cohort',
},
name: {
type: 'string',
description: 'Name of the cohort',
},
description: {
type: 'string',
description: 'Description of the cohort',
},
groups: {
type: 'array',
description: 'Groups that define the cohort',
},
deleted: {
type: 'boolean',
description: 'Whether the cohort is deleted',
},
filters: {
type: 'object',
description: 'Filter configuration for the cohort',
},
query: {
type: 'object',
description: 'Query configuration for the cohort',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when cohort was created',
},
created_by: {
type: 'object',
description: 'User who created the cohort',
optional: true,
},
is_calculating: {
type: 'boolean',
description: 'Whether the cohort is being calculated',
},
count: {
type: 'number',
description: 'Number of users in the cohort',
},
is_static: {
type: 'boolean',
description: 'Whether the cohort is static',
},
version: {
type: 'number',
description: 'Version number of the cohort',
},
},
}
+183
View File
@@ -0,0 +1,183 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogCreateDashboardParams {
apiKey: string
projectId: string
region?: 'us' | 'eu'
host?: string
name: string
description?: string
pinned?: boolean
tags?: string
useTemplate?: string
}
interface PostHogCreateDashboardResponse {
success: boolean
output: {
id: number
name: string
description: string
pinned: boolean
created_at: string
tiles: Array<Record<string, any>>
filters: Record<string, any>
tags: string[]
}
}
export const createDashboardTool: ToolConfig<
PostHogCreateDashboardParams,
PostHogCreateDashboardResponse
> = {
id: 'posthog_create_dashboard',
name: 'PostHog Create Dashboard',
description:
'Create a new dashboard in PostHog. Optionally seed it from a built-in template, then attach insights to it afterward.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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: true,
visibility: 'user-or-llm',
description: 'Name for the new dashboard',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the dashboard',
},
pinned: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to pin the dashboard to the sidebar',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of tags for the dashboard',
},
useTemplate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Name of a built-in PostHog dashboard template to seed this dashboard from (e.g., "Product analytics")',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/dashboards/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
}
if (params.description) body.description = params.description
if (params.pinned !== undefined) body.pinned = params.pinned
if (params.useTemplate) body.use_template = params.useTemplate
if (params.tags) {
body.tags = params.tags
.split(',')
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
pinned: data.pinned || false,
created_at: data.created_at,
tiles: data.tiles || [],
filters: data.filters || {},
tags: data.tags || [],
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the created dashboard',
},
name: {
type: 'string',
description: 'Name of the dashboard',
},
description: {
type: 'string',
description: 'Description of the dashboard',
},
pinned: {
type: 'boolean',
description: 'Whether the dashboard is pinned',
},
created_at: {
type: 'string',
description: 'ISO timestamp when dashboard was created',
},
tiles: {
type: 'array',
description: 'Tiles/widgets on the dashboard',
},
filters: {
type: 'object',
description: 'Global filters applied to the dashboard',
},
tags: {
type: 'array',
description: 'Tags associated with the dashboard',
},
},
}
+191
View File
@@ -0,0 +1,191 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface CreateExperimentParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
name: string
description?: string
featureFlagKey: string
parameters?: string
filters?: string
startDate?: string
endDate?: string
}
interface Experiment {
id: number
name: string
description: string
feature_flag_key: string
feature_flag: Record<string, any>
parameters: Record<string, any>
filters: Record<string, any>
start_date: string | null
end_date: string | null
created_at: string
created_by: Record<string, any>
archived: boolean
}
interface CreateExperimentResponse {
experiment: Experiment
}
export const createExperimentTool: ToolConfig<CreateExperimentParams, CreateExperimentResponse> = {
id: 'posthog_create_experiment',
name: 'PostHog Create Experiment',
description: 'Create a new experiment in PostHog',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Experiment name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Experiment description',
},
featureFlagKey: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Feature flag key to use for the experiment',
},
parameters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Experiment parameters as JSON string',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Experiment filters as JSON string',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Experiment start date (ISO format)',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Experiment end date (ISO format)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/experiments/`
},
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
feature_flag_key: params.featureFlagKey,
}
if (params.description !== undefined) {
body.description = params.description
}
if (params.parameters) {
try {
body.parameters = JSON.parse(params.parameters)
} catch (error) {
throw new Error(`Invalid parameters JSON: ${getErrorMessage(error)}`)
}
}
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (error) {
throw new Error(`Invalid filters JSON: ${getErrorMessage(error)}`)
}
}
if (params.startDate !== undefined) {
body.start_date = params.startDate
}
if (params.endDate !== undefined) {
body.end_date = params.endDate
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
experiment: data,
}
},
outputs: {
experiment: {
type: 'object',
description: 'Created experiment',
properties: {
id: { type: 'number', description: 'Experiment ID' },
name: { type: 'string', description: 'Experiment name' },
description: { type: 'string', description: 'Experiment description' },
feature_flag_key: { type: 'string', description: 'Associated feature flag key' },
feature_flag: { type: 'object', description: 'Feature flag details' },
parameters: { type: 'object', description: 'Experiment parameters' },
filters: { type: 'object', description: 'Experiment filters' },
start_date: { type: 'string', description: 'Start date' },
end_date: { type: 'string', description: 'End date' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
archived: { type: 'boolean', description: 'Whether the experiment is archived' },
},
},
},
}
@@ -0,0 +1,183 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface CreateFeatureFlagParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
name: string
key: string
filters?: string
active?: boolean
ensureExperienceContinuity?: boolean
rolloutPercentage?: number
}
interface FeatureFlag {
id: number
name: string
key: string
filters: Record<string, any>
deleted: boolean
active: boolean
created_at: string
created_by: Record<string, any>
is_simple_flag: boolean
rollout_percentage: number | null
ensure_experience_continuity: boolean
}
interface CreateFeatureFlagResponse {
flag: FeatureFlag
}
export const createFeatureFlagTool: ToolConfig<CreateFeatureFlagParams, CreateFeatureFlagResponse> =
{
id: 'posthog_create_feature_flag',
name: 'PostHog Create Feature Flag',
description: 'Create a new feature flag in PostHog',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag name (optional - can be empty)',
},
key: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Feature flag key (unique identifier)',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag filters as JSON string',
},
active: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the flag is active (default: true)',
default: true,
},
ensureExperienceContinuity: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to ensure experience continuity (default: false)',
default: false,
},
rolloutPercentage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Rollout percentage (0-100)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/feature_flags/`
},
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
key: params.key,
}
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (error) {
throw new Error(`Invalid filters JSON: ${getErrorMessage(error)}`)
}
}
if (params.active !== undefined) {
body.active = params.active
}
if (params.ensureExperienceContinuity !== undefined) {
body.ensure_experience_continuity = params.ensureExperienceContinuity
}
if (params.rolloutPercentage !== undefined) {
body.rollout_percentage = params.rolloutPercentage
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
flag: data,
}
},
outputs: {
flag: {
type: 'object',
description: 'Created feature flag',
properties: {
id: { type: 'number', description: 'Feature flag ID' },
name: { type: 'string', description: 'Feature flag name' },
key: { type: 'string', description: 'Feature flag key' },
filters: { type: 'object', description: 'Feature flag filters' },
deleted: { type: 'boolean', description: 'Whether the flag is deleted' },
active: { type: 'boolean', description: 'Whether the flag is active' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
is_simple_flag: { type: 'boolean', description: 'Whether this is a simple flag' },
rollout_percentage: {
type: 'number',
description: 'Rollout percentage (if applicable)',
},
ensure_experience_continuity: {
type: 'boolean',
description: 'Whether to ensure experience continuity',
},
},
},
},
}
+205
View File
@@ -0,0 +1,205 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogCreateInsightParams {
apiKey: string
projectId: string
region: string
host?: string
name: string
description?: string
query?: string
dashboards?: string
tags?: string
}
interface PostHogCreateInsightResponse {
success: boolean
output: {
id: number
name: string
description: string
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
last_modified_at: string
dashboards: number[]
tags: string[]
}
}
export const createInsightTool: ToolConfig<
PostHogCreateInsightParams,
PostHogCreateInsightResponse
> = {
id: 'posthog_create_insight',
name: 'PostHog Create Insight',
description: 'Create a new insight in PostHog. Requires insight name and a query configuration.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description:
'Name for the insight (optional - PostHog will generate a derived name if not provided)',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the insight',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of query configuration for the insight',
},
dashboards: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of dashboard IDs to add this insight to',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of tags for the insight',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/insights/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
}
if (params.description) {
body.description = params.description
}
if (params.query) {
try {
body.query = JSON.parse(params.query)
} catch (e) {
body.query = null
}
}
if (params.dashboards) {
body.dashboards = params.dashboards
.split(',')
.map((id: string) => Number(id.trim()))
.filter((id: number) => !Number.isNaN(id))
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
query: data.query || null,
created_at: data.created_at,
created_by: data.created_by || null,
last_modified_at: data.last_modified_at,
dashboards: data.dashboards || [],
tags: data.tags || [],
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the created insight',
},
name: {
type: 'string',
description: 'Name of the insight',
},
description: {
type: 'string',
description: 'Description of the insight',
},
query: {
type: 'object',
description: 'Query configuration for the insight',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when insight was created',
},
created_by: {
type: 'object',
description: 'User who created the insight',
optional: true,
},
last_modified_at: {
type: 'string',
description: 'ISO timestamp when insight was last modified',
},
dashboards: {
type: 'array',
description: 'IDs of dashboards this insight appears on',
},
tags: {
type: 'array',
description: 'Tags associated with the insight',
},
},
}
+227
View File
@@ -0,0 +1,227 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogSurveyQuestion {
type: 'open' | 'link' | 'rating' | 'multiple_choice'
question: string
description?: string
choices?: string[]
scale?: number
lowerBoundLabel?: string
upperBoundLabel?: string
buttonText?: string
}
interface PostHogCreateSurveyParams {
apiKey: string
projectId: string
region?: 'us' | 'eu'
host?: string
name: string
description?: string
type?: 'popover' | 'api'
questions: string // JSON string of questions array
startDate?: string
endDate?: string
appearance?: string // JSON string of appearance config
conditions?: string // JSON string of conditions
targetingFlagFilters?: string // JSON string of targeting filters
linkedFlagId?: string
responsesLimit?: number
}
interface PostHogSurvey {
id: string
name: string
description: string
type: 'popover' | 'api'
questions: PostHogSurveyQuestion[]
appearance?: Record<string, any>
conditions?: Record<string, any>
created_at: string
created_by: Record<string, any>
start_date?: string
end_date?: string
archived?: boolean
targeting_flag_filters?: Record<string, any>
linked_flag?: Record<string, any>
responses_limit?: number
}
interface PostHogCreateSurveyResponse {
success: boolean
output: {
survey: PostHogSurvey
}
}
export const createSurveyTool: ToolConfig<PostHogCreateSurveyParams, PostHogCreateSurveyResponse> =
{
id: 'posthog_create_survey',
name: 'PostHog Create Survey',
description:
'Create a new survey in PostHog. Supports question types: Basic (open), Link, Rating, and Multiple Choice.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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: true,
visibility: 'user-or-llm',
description: 'Survey name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey description',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Survey type: popover (in-app) or api (custom implementation) (default: popover)',
default: 'popover',
},
questions: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON string of survey questions array. Each question must have type (open/link/rating/multiple_choice) and question text. Rating questions can have scale (1-10), lowerBoundLabel, upperBoundLabel. Multiple choice questions need choices array. Link questions can have buttonText.',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey start date in ISO 8601 format',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey end date in ISO 8601 format',
},
appearance: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of appearance configuration (colors, position, etc.)',
},
conditions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of display conditions (URL matching, etc.)',
},
targetingFlagFilters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of feature flag filters for targeting',
},
linkedFlagId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag ID to link to this survey',
},
responsesLimit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of responses to collect',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/surveys/`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
type: params.type || 'popover',
questions: JSON.parse(params.questions),
}
if (params.description) body.description = params.description
if (params.startDate) body.start_date = params.startDate
if (params.endDate) body.end_date = params.endDate
if (params.appearance) body.appearance = JSON.parse(params.appearance)
if (params.conditions) body.conditions = JSON.parse(params.conditions)
if (params.targetingFlagFilters) {
body.targeting_flag_filters = JSON.parse(params.targetingFlagFilters)
}
if (params.linkedFlagId) body.linked_flag_id = params.linkedFlagId
if (params.responsesLimit) body.responses_limit = params.responsesLimit
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
survey: data,
},
}
},
outputs: {
survey: {
type: 'object',
description: 'Created survey details',
properties: {
id: { type: 'string', description: 'Survey ID' },
name: { type: 'string', description: 'Survey name' },
description: { type: 'string', description: 'Survey description' },
type: { type: 'string', description: 'Survey type (popover or api)' },
questions: {
type: 'array',
description: 'Survey questions',
},
created_at: { type: 'string', description: 'Creation timestamp' },
start_date: { type: 'string', description: 'Survey start date' },
end_date: { type: 'string', description: 'Survey end date' },
},
},
},
}
@@ -0,0 +1,91 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface DeleteFeatureFlagParams {
projectId: string
flagId: string
region: 'us' | 'eu'
host?: string
apiKey: string
}
interface DeleteFeatureFlagResponse {
success: boolean
message: string
}
export const deleteFeatureFlagTool: ToolConfig<DeleteFeatureFlagParams, DeleteFeatureFlagResponse> =
{
id: 'posthog_delete_feature_flag',
name: 'PostHog Delete Feature Flag',
description: 'Delete a feature flag from PostHog',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
flagId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The feature flag ID to delete (e.g., "42")',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/feature_flags/${params.flagId}/`
},
// PostHog does not allow a hard DELETE on feature flags (always returns 405).
// Deletion is a soft-delete via PATCH with deleted: true.
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: () => ({ deleted: true }),
},
transformResponse: async () => {
return {
success: true,
message: 'Feature flag deleted successfully',
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the deletion was successful',
},
message: {
type: 'string',
description: 'Confirmation message',
},
},
}
+95
View File
@@ -0,0 +1,95 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogDeletePersonParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
projectId: string
personId: string
}
export interface PostHogDeletePersonResponse {
success: boolean
output: {
status: string
}
}
export const deletePersonTool: ToolConfig<PostHogDeletePersonParams, PostHogDeletePersonResponse> =
{
id: 'posthog_delete_person',
name: 'PostHog Delete Person',
description:
'Delete a person from PostHog. This will remove all associated events and data. Use with caution.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key (for authenticated API access)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
personId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Person ID or UUID to delete (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
},
request: {
// PostHog has no single-person DELETE endpoint; deletion is only available
// via the bulk_delete endpoint, called here with a single ID.
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/persons/bulk_delete/`
},
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => ({ ids: [params.personId] }),
},
transformResponse: async (response: Response) => {
const data = await response.json()
const success = data.persons_deleted > 0
return {
success,
output: {
status: success ? 'Person deleted successfully' : 'No matching person found to delete',
},
}
},
outputs: {
status: {
type: 'string',
description: 'Status message indicating whether the person was deleted successfully',
},
},
}
+89
View File
@@ -0,0 +1,89 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogDeleteSurveyParams {
apiKey: string
projectId: string
surveyId: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogDeleteSurveyResponse {
success: boolean
output: {
status: string
}
}
export const deleteSurveyTool: ToolConfig<PostHogDeleteSurveyParams, PostHogDeleteSurveyResponse> =
{
id: 'posthog_delete_survey',
name: 'PostHog Delete Survey',
description: 'Delete a survey from PostHog. Use this to remove expired or unused surveys.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
surveyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Survey ID to delete (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/surveys/${params.surveyId}/`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async () => {
return {
success: true,
output: {
status: 'Survey deleted successfully',
},
}
},
outputs: {
status: {
type: 'string',
description: 'Status message indicating whether the survey was deleted successfully',
},
},
}
+164
View File
@@ -0,0 +1,164 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogIngestBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface EvaluateFlagsParams {
region: 'us' | 'eu'
host?: string
projectApiKey: string
distinctId: string
groups?: string
personProperties?: string
groupProperties?: string
}
interface FlagEvaluation {
[key: string]: boolean | string
}
interface EvaluateFlagsResponse {
feature_flags: FlagEvaluation
feature_flag_payloads: Record<string, any>
errors_while_computing_flags: boolean
}
export const evaluateFlagsTool: ToolConfig<EvaluateFlagsParams, EvaluateFlagsResponse> = {
id: 'posthog_evaluate_flags',
name: 'PostHog Evaluate Feature Flags',
description:
'Evaluate feature flags for a specific user or group. This is a public endpoint that uses the project API key.',
version: '1.0.0',
params: {
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
projectApiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Project API Key (not personal API key)',
},
distinctId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The distinct ID of the user to evaluate flags for (e.g., "user123" or email)',
},
groups: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Groups as JSON string (e.g., {"company": "company_id_in_your_db"})',
},
personProperties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Person properties as JSON string',
},
groupProperties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Group properties as JSON string',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogIngestBaseUrl(params.region, params.host)
return `${baseUrl}/flags/?v=2`
},
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
api_key: params.projectApiKey,
distinct_id: params.distinctId,
}
if (params.groups) {
try {
body.groups = JSON.parse(params.groups)
} catch (error) {
throw new Error(`Invalid groups JSON: ${getErrorMessage(error)}`)
}
}
if (params.personProperties) {
try {
body.person_properties = JSON.parse(params.personProperties)
} catch (error) {
throw new Error(`Invalid personProperties JSON: ${getErrorMessage(error)}`)
}
}
if (params.groupProperties) {
try {
body.group_properties = JSON.parse(params.groupProperties)
} catch (error) {
throw new Error(`Invalid groupProperties JSON: ${getErrorMessage(error)}`)
}
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
const flags: Record<
string,
{ enabled?: boolean; variant?: string; metadata?: { payload?: string } }
> = data.flags || {}
const feature_flags: FlagEvaluation = {}
const feature_flag_payloads: Record<string, any> = {}
for (const [key, flag] of Object.entries(flags)) {
feature_flags[key] = flag.variant ?? flag.enabled ?? false
if (flag.metadata?.payload !== undefined) {
try {
feature_flag_payloads[key] = JSON.parse(flag.metadata.payload)
} catch {
feature_flag_payloads[key] = flag.metadata.payload
}
}
}
return {
feature_flags,
feature_flag_payloads,
errors_while_computing_flags: data.errorsWhileComputingFlags || false,
}
},
outputs: {
feature_flags: {
type: 'object',
description:
'Feature flag evaluations (key-value pairs where values are boolean or string variants)',
},
feature_flag_payloads: {
type: 'object',
description: 'Additional payloads attached to feature flags',
},
errors_while_computing_flags: {
type: 'boolean',
description: 'Whether there were errors while computing flags',
},
},
}
+177
View File
@@ -0,0 +1,177 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetCohortParams {
apiKey: string
projectId: string
cohortId: string
region: string
host?: string
}
interface PostHogGetCohortResponse {
success: boolean
output: {
id: number
name: string
description: string
groups: Array<Record<string, any>>
deleted: boolean
filters: Record<string, any>
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
is_calculating: boolean
last_calculation: string
errors_calculating: number
count: number
is_static: boolean
version: number
}
}
export const getCohortTool: ToolConfig<PostHogGetCohortParams, PostHogGetCohortResponse> = {
id: 'posthog_get_cohort',
name: 'PostHog Get Cohort',
description:
'Get a specific cohort by ID from PostHog. Returns detailed cohort definition, filters, and user count.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
cohortId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The cohort ID to retrieve (e.g., "42")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/cohorts/${params.cohortId}/`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
groups: data.groups || [],
deleted: data.deleted || false,
filters: data.filters || {},
query: data.query || null,
created_at: data.created_at,
created_by: data.created_by || null,
is_calculating: data.is_calculating || false,
last_calculation: data.last_calculation || '',
errors_calculating: data.errors_calculating || 0,
count: data.count || 0,
is_static: data.is_static || false,
version: data.version || 0,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the cohort',
},
name: {
type: 'string',
description: 'Name of the cohort',
},
description: {
type: 'string',
description: 'Description of the cohort',
},
groups: {
type: 'array',
description: 'Groups that define the cohort',
},
deleted: {
type: 'boolean',
description: 'Whether the cohort is deleted',
},
filters: {
type: 'object',
description: 'Filter configuration for the cohort',
},
query: {
type: 'object',
description: 'Query configuration for the cohort',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when cohort was created',
},
created_by: {
type: 'object',
description: 'User who created the cohort',
optional: true,
},
is_calculating: {
type: 'boolean',
description: 'Whether the cohort is being calculated',
},
last_calculation: {
type: 'string',
description: 'ISO timestamp of last calculation',
},
errors_calculating: {
type: 'number',
description: 'Number of errors during calculation',
},
count: {
type: 'number',
description: 'Number of users in the cohort',
},
is_static: {
type: 'boolean',
description: 'Whether the cohort is static',
},
version: {
type: 'number',
description: 'Version number of the cohort',
},
},
}
+160
View File
@@ -0,0 +1,160 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetDashboardParams {
apiKey: string
projectId: string
dashboardId: string
region: string
host?: string
}
interface PostHogGetDashboardResponse {
success: boolean
output: {
id: number
name: string
description: string
pinned: boolean
created_at: string
created_by: Record<string, any> | null
last_modified_at: string
last_modified_by: Record<string, any> | null
tiles: Array<Record<string, any>>
filters: Record<string, any>
tags: string[]
restriction_level: number
}
}
export const getDashboardTool: ToolConfig<PostHogGetDashboardParams, PostHogGetDashboardResponse> =
{
id: 'posthog_get_dashboard',
name: 'PostHog Get Dashboard',
description:
'Get a specific dashboard by ID from PostHog. Returns detailed dashboard configuration, tiles, and metadata.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
dashboardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The dashboard ID to retrieve (e.g., "42")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/dashboards/${params.dashboardId}/`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
pinned: data.pinned || false,
created_at: data.created_at,
created_by: data.created_by || null,
last_modified_at: data.last_modified_at,
last_modified_by: data.last_modified_by || null,
tiles: data.tiles || [],
filters: data.filters || {},
tags: data.tags || [],
restriction_level: data.restriction_level || 0,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the dashboard',
},
name: {
type: 'string',
description: 'Name of the dashboard',
},
description: {
type: 'string',
description: 'Description of the dashboard',
},
pinned: {
type: 'boolean',
description: 'Whether the dashboard is pinned',
},
created_at: {
type: 'string',
description: 'ISO timestamp when dashboard was created',
},
created_by: {
type: 'object',
description: 'User who created the dashboard',
optional: true,
},
last_modified_at: {
type: 'string',
description: 'ISO timestamp when dashboard was last modified',
},
last_modified_by: {
type: 'object',
description: 'User who last modified the dashboard',
optional: true,
},
tiles: {
type: 'array',
description: 'Tiles/widgets on the dashboard with their configurations',
},
filters: {
type: 'object',
description: 'Global filters applied to the dashboard',
},
tags: {
type: 'array',
description: 'Tags associated with the dashboard',
},
restriction_level: {
type: 'number',
description: 'Access restriction level for the dashboard',
},
},
}
@@ -0,0 +1,155 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetEventDefinitionParams {
projectId: string
eventDefinitionId: string
region: 'us' | 'eu'
host?: string
apiKey: string
}
interface EventDefinition {
id: string
name: string
description: string
tags: string[]
created_at: string
last_seen_at: string | null
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
verified: boolean
verified_at: string | null
verified_by: string | null
}
export const getEventDefinitionTool: ToolConfig<PostHogGetEventDefinitionParams, EventDefinition> =
{
id: 'posthog_get_event_definition',
name: 'PostHog Get Event Definition',
description:
'Get details of a specific event definition in PostHog. Returns comprehensive information about the event including metadata, usage statistics, and verification status.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
eventDefinitionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Event Definition ID to retrieve',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/event_definitions/${params.eventDefinitionId}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
id: data.id,
name: data.name,
description: data.description || '',
tags: data.tags || [],
created_at: data.created_at,
last_seen_at: data.last_seen_at ?? null,
updated_at: data.updated_at,
updated_by: data.updated_by ?? null,
verified: data.verified || false,
verified_at: data.verified_at ?? null,
verified_by: data.verified_by ?? null,
}
},
outputs: {
id: {
type: 'string',
description: 'Unique identifier for the event definition',
},
name: {
type: 'string',
description: 'Event name',
},
description: {
type: 'string',
description: 'Event description',
},
tags: {
type: 'array',
description: 'Tags associated with the event',
},
created_at: {
type: 'string',
description: 'ISO timestamp when the event was created',
},
last_seen_at: {
type: 'string',
description: 'ISO timestamp when the event was last seen',
optional: true,
},
updated_at: {
type: 'string',
description: 'ISO timestamp when the event was updated',
},
updated_by: {
type: 'object',
description: 'User who last updated the event',
optional: true,
},
verified: {
type: 'boolean',
description: 'Whether the event has been verified',
},
verified_at: {
type: 'string',
description: 'ISO timestamp when the event was verified',
optional: true,
},
verified_by: {
type: 'string',
description: 'User who verified the event',
optional: true,
},
},
}
+116
View File
@@ -0,0 +1,116 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface GetExperimentParams {
projectId: string
experimentId: string
region: 'us' | 'eu'
host?: string
apiKey: string
}
interface Experiment {
id: number
name: string
description: string
feature_flag_key: string
feature_flag: Record<string, any>
parameters: Record<string, any>
filters: Record<string, any>
start_date: string | null
end_date: string | null
created_at: string
created_by: Record<string, any>
archived: boolean
metrics: Array<Record<string, any>>
metrics_secondary: Array<Record<string, any>>
}
interface GetExperimentResponse {
experiment: Experiment
}
export const getExperimentTool: ToolConfig<GetExperimentParams, GetExperimentResponse> = {
id: 'posthog_get_experiment',
name: 'PostHog Get Experiment',
description: 'Get details of a specific experiment',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
experimentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The experiment ID (e.g., "42")',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/experiments/${params.experimentId}/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
experiment: data,
}
},
outputs: {
experiment: {
type: 'object',
description: 'Experiment details',
properties: {
id: { type: 'number', description: 'Experiment ID' },
name: { type: 'string', description: 'Experiment name' },
description: { type: 'string', description: 'Experiment description' },
feature_flag_key: { type: 'string', description: 'Associated feature flag key' },
feature_flag: { type: 'object', description: 'Feature flag details' },
parameters: { type: 'object', description: 'Experiment parameters' },
filters: { type: 'object', description: 'Experiment filters' },
start_date: { type: 'string', description: 'Start date' },
end_date: { type: 'string', description: 'End date' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
archived: { type: 'boolean', description: 'Whether the experiment is archived' },
metrics: { type: 'array', description: 'Primary metrics' },
metrics_secondary: { type: 'array', description: 'Secondary metrics' },
},
},
},
}
+127
View File
@@ -0,0 +1,127 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface GetFeatureFlagParams {
projectId: string
flagId: string
region: 'us' | 'eu'
host?: string
apiKey: string
}
interface FeatureFlag {
id: number
name: string
key: string
filters: Record<string, any>
deleted: boolean
active: boolean
created_at: string
created_by: Record<string, any>
is_simple_flag: boolean
rollout_percentage: number | null
ensure_experience_continuity: boolean
usage_dashboard: number | null
has_enriched_analytics: boolean
}
interface GetFeatureFlagResponse {
flag: FeatureFlag
}
export const getFeatureFlagTool: ToolConfig<GetFeatureFlagParams, GetFeatureFlagResponse> = {
id: 'posthog_get_feature_flag',
name: 'PostHog Get Feature Flag',
description: 'Get details of a specific feature flag',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
flagId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The feature flag ID (e.g., "42")',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/feature_flags/${params.flagId}/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
flag: data,
}
},
outputs: {
flag: {
type: 'object',
description: 'Feature flag details',
properties: {
id: { type: 'number', description: 'Feature flag ID' },
name: { type: 'string', description: 'Feature flag name' },
key: { type: 'string', description: 'Feature flag key' },
filters: { type: 'object', description: 'Feature flag filters' },
deleted: { type: 'boolean', description: 'Whether the flag is deleted' },
active: { type: 'boolean', description: 'Whether the flag is active' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
is_simple_flag: { type: 'boolean', description: 'Whether this is a simple flag' },
rollout_percentage: {
type: 'number',
description: 'Rollout percentage (if applicable)',
},
ensure_experience_continuity: {
type: 'boolean',
description: 'Whether to ensure experience continuity',
},
usage_dashboard: {
type: 'number',
description: 'Usage dashboard ID',
optional: true,
},
has_enriched_analytics: {
type: 'boolean',
description: 'Whether enriched analytics are enabled',
},
},
},
},
}
+154
View File
@@ -0,0 +1,154 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetInsightParams {
apiKey: string
projectId: string
insightId: string
region: string
host?: string
}
interface PostHogGetInsightResponse {
success: boolean
output: {
id: number
name: string
description: string
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
last_modified_at: string
last_modified_by: Record<string, any> | null
dashboards: number[]
tags: string[]
favorited: boolean
}
}
export const getInsightTool: ToolConfig<PostHogGetInsightParams, PostHogGetInsightResponse> = {
id: 'posthog_get_insight',
name: 'PostHog Get Insight',
description:
'Get a specific insight by ID from PostHog. Returns detailed insight configuration and metadata.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
insightId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The insight ID to retrieve (e.g., "42" or short ID like "abc123")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
return `${baseUrl}/api/projects/${params.projectId}/insights/${params.insightId}/`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
query: data.query || null,
created_at: data.created_at,
created_by: data.created_by || null,
last_modified_at: data.last_modified_at,
last_modified_by: data.last_modified_by || null,
dashboards: data.dashboards || [],
tags: data.tags || [],
favorited: data.favorited || false,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the insight',
},
name: {
type: 'string',
description: 'Name of the insight',
},
description: {
type: 'string',
description: 'Description of the insight',
},
query: {
type: 'object',
description: 'Query configuration for the insight',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when insight was created',
},
created_by: {
type: 'object',
description: 'User who created the insight',
optional: true,
},
last_modified_at: {
type: 'string',
description: 'ISO timestamp when insight was last modified',
},
last_modified_by: {
type: 'object',
description: 'User who last modified the insight',
optional: true,
},
dashboards: {
type: 'array',
description: 'IDs of dashboards this insight appears on',
},
tags: {
type: 'array',
description: 'Tags associated with the insight',
},
favorited: {
type: 'boolean',
description: 'Whether the insight is favorited',
},
},
}
+163
View File
@@ -0,0 +1,163 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogGetOrganizationParams {
organizationId: string
apiKey: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogOrganizationDetail {
id: string
name: string
slug: string
created_at: string
updated_at: string
membership_level: number
plugins_access_level: number
teams: number[]
available_product_features: Array<{
key: string
name: string
description: string
unit: string
limit: number | null
note: string | null
}>
domain_whitelist: string[]
is_member_join_email_enabled: boolean
metadata: Record<string, any>
customer_id: string | null
available_features: string[]
usage: Record<string, any> | null
}
export interface PostHogGetOrganizationResponse {
success: boolean
output: {
organization: PostHogOrganizationDetail
}
error?: string
}
export const getOrganizationTool: ToolConfig<
PostHogGetOrganizationParams,
PostHogGetOrganizationResponse
> = {
id: 'posthog_get_organization',
name: 'PostHog Get Organization',
description:
'Get detailed information about a specific organization by ID. Returns comprehensive organization settings, features, usage, and team information.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
organizationId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Organization ID (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cloud region: us 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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/organizations/${params.organizationId}/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
organization: {
id: data.id,
name: data.name,
slug: data.slug,
created_at: data.created_at,
updated_at: data.updated_at,
membership_level: data.membership_level,
plugins_access_level: data.plugins_access_level,
teams: data.teams || [],
available_product_features: data.available_product_features || [],
domain_whitelist: data.domain_whitelist || [],
is_member_join_email_enabled: data.is_member_join_email_enabled,
metadata: data.metadata || {},
customer_id: data.customer_id ?? null,
available_features: data.available_features || [],
usage: data.usage ?? null,
},
},
}
},
outputs: {
organization: {
type: 'object',
description: 'Detailed organization information with settings and features',
properties: {
id: { type: 'string', description: 'Organization ID (UUID)' },
name: { type: 'string', description: 'Organization name' },
slug: { type: 'string', description: 'Organization slug' },
created_at: { type: 'string', description: 'Organization creation timestamp' },
updated_at: { type: 'string', description: 'Last update timestamp' },
membership_level: {
type: 'number',
description: 'User membership level in organization',
},
plugins_access_level: {
type: 'number',
description: 'Access level for plugins/apps',
},
teams: { type: 'array', description: 'List of team IDs in this organization' },
available_product_features: {
type: 'array',
description: 'Available product features with their limits and descriptions',
},
domain_whitelist: {
type: 'array',
description: 'Whitelisted domains for organization',
},
is_member_join_email_enabled: {
type: 'boolean',
description: 'Whether member join emails are enabled',
},
metadata: { type: 'object', description: 'Organization metadata' },
customer_id: { type: 'string', description: 'Customer ID for billing', optional: true },
available_features: {
type: 'array',
description: 'List of available feature flags for organization',
},
usage: { type: 'object', description: 'Organization usage statistics', optional: true },
},
},
},
}
+115
View File
@@ -0,0 +1,115 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogGetPersonParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
projectId: string
personId: string
}
export interface PostHogGetPersonResponse {
success: boolean
output: {
person: {
id: string
name: string
distinct_ids: string[]
properties: Record<string, any>
created_at: string
uuid: string
}
}
}
export const getPersonTool: ToolConfig<PostHogGetPersonParams, PostHogGetPersonResponse> = {
id: 'posthog_get_person',
name: 'PostHog Get Person',
description: 'Get detailed information about a specific person in PostHog by their ID or UUID.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key (for authenticated API access)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
personId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Person ID or UUID to retrieve (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/persons/${params.personId}/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
person: {
id: data.id,
name: data.name || '',
distinct_ids: data.distinct_ids || [],
properties: data.properties || {},
created_at: data.created_at,
uuid: data.uuid,
},
},
}
},
outputs: {
person: {
type: 'object',
description: 'Person details including properties and identifiers',
properties: {
id: { type: 'string', description: 'Person ID' },
name: { type: 'string', description: 'Person name' },
distinct_ids: {
type: 'array',
description: 'All distinct IDs associated with this person',
},
properties: { type: 'object', description: 'Person properties' },
created_at: { type: 'string', description: 'When the person was first seen' },
uuid: { type: 'string', description: 'Person UUID' },
},
},
},
}
+187
View File
@@ -0,0 +1,187 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogGetProjectParams {
projectId: string
apiKey: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogProjectDetail {
id: number
uuid: string
organization: string
api_token: string
app_urls: string[]
name: string
slack_incoming_webhook: string
created_at: string
updated_at: string
anonymize_ips: boolean
completed_snippet_onboarding: boolean
ingested_event: boolean
test_account_filters: any[]
is_demo: boolean
timezone: string
data_attributes: string[]
person_display_name_properties: string[]
correlation_config: {
excluded_person_property_names?: string[]
excluded_event_names?: string[]
excluded_event_property_names?: string[]
}
autocapture_opt_out: boolean
autocapture_exceptions_opt_in: boolean
session_recording_opt_in: boolean
capture_console_log_opt_in: boolean
capture_performance_opt_in: boolean
}
export interface PostHogGetProjectResponse {
success: boolean
output: {
project: PostHogProjectDetail
}
error?: string
}
export const getProjectTool: ToolConfig<PostHogGetProjectParams, PostHogGetProjectResponse> = {
id: 'posthog_get_project',
name: 'PostHog Get Project',
description:
'Get detailed information about a specific project by ID. Returns comprehensive project configuration, settings, and feature flags.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Project ID (e.g., "12345" or project UUID)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cloud region: us 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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
project: {
id: data.id,
uuid: data.uuid,
organization: data.organization,
api_token: data.api_token,
app_urls: data.app_urls || [],
name: data.name,
slack_incoming_webhook: data.slack_incoming_webhook,
created_at: data.created_at,
updated_at: data.updated_at,
anonymize_ips: data.anonymize_ips,
completed_snippet_onboarding: data.completed_snippet_onboarding,
ingested_event: data.ingested_event,
test_account_filters: data.test_account_filters || [],
is_demo: data.is_demo,
timezone: data.timezone,
data_attributes: data.data_attributes || [],
person_display_name_properties: data.person_display_name_properties || [],
correlation_config: data.correlation_config || {},
autocapture_opt_out: data.autocapture_opt_out,
autocapture_exceptions_opt_in: data.autocapture_exceptions_opt_in,
session_recording_opt_in: data.session_recording_opt_in,
capture_console_log_opt_in: data.capture_console_log_opt_in,
capture_performance_opt_in: data.capture_performance_opt_in,
},
},
}
},
outputs: {
project: {
type: 'object',
description: 'Detailed project information with all configuration settings',
properties: {
id: { type: 'number', description: 'Project ID' },
uuid: { type: 'string', description: 'Project UUID' },
organization: { type: 'string', description: 'Organization UUID' },
api_token: { type: 'string', description: 'Project API token for ingestion' },
app_urls: { type: 'array', description: 'Allowed app URLs' },
name: { type: 'string', description: 'Project name' },
slack_incoming_webhook: {
type: 'string',
description: 'Slack webhook URL for notifications',
},
created_at: { type: 'string', description: 'Project creation timestamp' },
updated_at: { type: 'string', description: 'Last update timestamp' },
anonymize_ips: { type: 'boolean', description: 'Whether IP anonymization is enabled' },
completed_snippet_onboarding: {
type: 'boolean',
description: 'Whether snippet onboarding is completed',
},
ingested_event: { type: 'boolean', description: 'Whether any event has been ingested' },
test_account_filters: { type: 'array', description: 'Filters for test accounts' },
is_demo: { type: 'boolean', description: 'Whether this is a demo project' },
timezone: { type: 'string', description: 'Project timezone' },
data_attributes: { type: 'array', description: 'Custom data attributes' },
person_display_name_properties: {
type: 'array',
description: 'Properties used for person display names',
},
correlation_config: {
type: 'object',
description: 'Configuration for correlation analysis',
},
autocapture_opt_out: { type: 'boolean', description: 'Whether autocapture is disabled' },
autocapture_exceptions_opt_in: {
type: 'boolean',
description: 'Whether exception autocapture is enabled',
},
session_recording_opt_in: {
type: 'boolean',
description: 'Whether session recording is enabled',
},
capture_console_log_opt_in: {
type: 'boolean',
description: 'Whether console log capture is enabled',
},
capture_performance_opt_in: {
type: 'boolean',
description: 'Whether performance capture is enabled',
},
},
},
},
}
@@ -0,0 +1,175 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetPropertyDefinitionParams {
projectId: string
propertyDefinitionId: string
region: 'us' | 'eu'
host?: string
apiKey: string
}
interface PropertyDefinition {
id: string
name: string
description: string
tags: string[]
is_numerical: boolean
is_seen_on_filtered_events: boolean | null
property_type: string
type: 'event' | 'person' | 'group' | 'session'
created_at: string
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
verified: boolean
verified_at: string | null
verified_by: string | null
}
export const getPropertyDefinitionTool: ToolConfig<
PostHogGetPropertyDefinitionParams,
PropertyDefinition
> = {
id: 'posthog_get_property_definition',
name: 'PostHog Get Property Definition',
description:
'Get details of a specific property definition in PostHog. Returns comprehensive information about the property including metadata, type, usage statistics, and verification status.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
propertyDefinitionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Property Definition ID to retrieve',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/property_definitions/${params.propertyDefinitionId}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
id: data.id,
name: data.name,
description: data.description || '',
tags: data.tags || [],
is_numerical: data.is_numerical || false,
is_seen_on_filtered_events: data.is_seen_on_filtered_events ?? null,
property_type: data.property_type,
type: data.type,
created_at: data.created_at,
updated_at: data.updated_at,
updated_by: data.updated_by ?? null,
verified: data.verified || false,
verified_at: data.verified_at ?? null,
verified_by: data.verified_by ?? null,
}
},
outputs: {
id: {
type: 'string',
description: 'Unique identifier for the property definition',
},
name: {
type: 'string',
description: 'Property name',
},
description: {
type: 'string',
description: 'Property description',
},
tags: {
type: 'array',
description: 'Tags associated with the property',
},
is_numerical: {
type: 'boolean',
description: 'Whether the property is numerical',
},
is_seen_on_filtered_events: {
type: 'boolean',
description: 'Whether the property is seen on filtered events',
optional: true,
},
property_type: {
type: 'string',
description: 'The data type of the property',
},
type: {
type: 'string',
description: 'Property type: event, person, group, or session',
},
created_at: {
type: 'string',
description: 'ISO timestamp when the property was created',
},
updated_at: {
type: 'string',
description: 'ISO timestamp when the property was updated',
},
updated_by: {
type: 'object',
description: 'User who last updated the property',
optional: true,
},
verified: {
type: 'boolean',
description: 'Whether the property has been verified',
},
verified_at: {
type: 'string',
description: 'ISO timestamp when the property was verified',
optional: true,
},
verified_by: {
type: 'string',
description: 'User who verified the property',
optional: true,
},
},
}
@@ -0,0 +1,133 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetSessionRecordingParams {
apiKey: string
projectId: string
recordingId: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogSessionRecording {
id: string
distinct_id: string
viewed: boolean
recording_duration: number
active_seconds: number
inactive_seconds: number
start_time: string
end_time: string
click_count: number
keypress_count: number
console_log_count: number
console_warn_count: number
console_error_count: number
start_url?: string
person?: {
id: string
name?: string
properties?: Record<string, any>
}
}
interface PostHogGetSessionRecordingResponse {
success: boolean
output: {
recording: PostHogSessionRecording
}
}
export const getSessionRecordingTool: ToolConfig<
PostHogGetSessionRecordingParams,
PostHogGetSessionRecordingResponse
> = {
id: 'posthog_get_session_recording',
name: 'PostHog Get Session Recording',
description: 'Get details of a specific session recording in PostHog by ID.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
recordingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Session recording ID to retrieve (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/session_recordings/${params.recordingId}/`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
recording: data,
},
}
},
outputs: {
recording: {
type: 'object',
description: 'Session recording details',
properties: {
id: { type: 'string', description: 'Recording ID' },
distinct_id: { type: 'string', description: 'User distinct ID' },
viewed: { type: 'boolean', description: 'Whether recording has been viewed' },
recording_duration: { type: 'number', description: 'Recording duration in seconds' },
active_seconds: { type: 'number', description: 'Active time in seconds' },
inactive_seconds: { type: 'number', description: 'Inactive time in seconds' },
start_time: { type: 'string', description: 'Recording start timestamp' },
end_time: { type: 'string', description: 'Recording end timestamp' },
click_count: { type: 'number', description: 'Number of clicks' },
keypress_count: { type: 'number', description: 'Number of keypresses' },
console_log_count: { type: 'number', description: 'Number of console logs' },
console_warn_count: { type: 'number', description: 'Number of console warnings' },
console_error_count: { type: 'number', description: 'Number of console errors' },
start_url: { type: 'string', description: 'Starting URL of the recording' },
person: { type: 'object', description: 'Person information' },
},
},
},
}
+143
View File
@@ -0,0 +1,143 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogGetSurveyParams {
apiKey: string
projectId: string
surveyId: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogSurveyQuestion {
type: 'open' | 'link' | 'rating' | 'multiple_choice'
question: string
description?: string
choices?: string[]
scale?: number
lowerBoundLabel?: string
upperBoundLabel?: string
}
interface PostHogSurvey {
id: string
name: string
description: string
type: 'popover' | 'api'
questions: PostHogSurveyQuestion[]
appearance?: Record<string, any>
conditions?: Record<string, any>
created_at: string
created_by: Record<string, any>
start_date?: string
end_date?: string
archived?: boolean
targeting_flag_filters?: Record<string, any>
linked_flag?: Record<string, any>
responses_limit?: number
current_iteration?: number
}
interface PostHogGetSurveyResponse {
success: boolean
output: {
survey: PostHogSurvey
}
}
export const getSurveyTool: ToolConfig<PostHogGetSurveyParams, PostHogGetSurveyResponse> = {
id: 'posthog_get_survey',
name: 'PostHog Get Survey',
description: 'Get details of a specific survey in PostHog by ID.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
surveyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Survey ID to retrieve (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/surveys/${params.surveyId}/`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
survey: data,
},
}
},
outputs: {
survey: {
type: 'object',
description: 'Survey details',
properties: {
id: { type: 'string', description: 'Survey ID' },
name: { type: 'string', description: 'Survey name' },
description: { type: 'string', description: 'Survey description' },
type: { type: 'string', description: 'Survey type (popover or api)' },
questions: {
type: 'array',
description: 'Survey questions',
},
appearance: {
type: 'object',
description: 'Survey appearance configuration',
},
conditions: {
type: 'object',
description: 'Survey display conditions',
},
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
start_date: { type: 'string', description: 'Survey start date' },
end_date: { type: 'string', description: 'Survey end date' },
archived: { type: 'boolean', description: 'Whether survey is archived' },
responses_limit: { type: 'number', description: 'Maximum number of responses' },
},
},
},
}
+110
View File
@@ -0,0 +1,110 @@
// Core Data Operations
import { batchEventsTool } from '@/tools/posthog/batch_events'
import { captureEventTool } from '@/tools/posthog/capture_event'
import { createAnnotationTool } from '@/tools/posthog/create_annotation'
import { createCohortTool } from '@/tools/posthog/create_cohort'
import { createDashboardTool } from '@/tools/posthog/create_dashboard'
import { createExperimentTool } from '@/tools/posthog/create_experiment'
import { createFeatureFlagTool } from '@/tools/posthog/create_feature_flag'
import { createInsightTool } from '@/tools/posthog/create_insight'
import { createSurveyTool } from '@/tools/posthog/create_survey'
import { deleteFeatureFlagTool } from '@/tools/posthog/delete_feature_flag'
import { deletePersonTool } from '@/tools/posthog/delete_person'
import { deleteSurveyTool } from '@/tools/posthog/delete_survey'
import { evaluateFlagsTool } from '@/tools/posthog/evaluate_flags'
import { getCohortTool } from '@/tools/posthog/get_cohort'
import { getDashboardTool } from '@/tools/posthog/get_dashboard'
import { getEventDefinitionTool } from '@/tools/posthog/get_event_definition'
import { getExperimentTool } from '@/tools/posthog/get_experiment'
import { getFeatureFlagTool } from '@/tools/posthog/get_feature_flag'
import { getInsightTool } from '@/tools/posthog/get_insight'
import { getOrganizationTool } from '@/tools/posthog/get_organization'
import { getPersonTool } from '@/tools/posthog/get_person'
import { getProjectTool } from '@/tools/posthog/get_project'
import { getPropertyDefinitionTool } from '@/tools/posthog/get_property_definition'
import { getSessionRecordingTool } from '@/tools/posthog/get_session_recording'
import { getSurveyTool } from '@/tools/posthog/get_survey'
import { listActionsTool } from '@/tools/posthog/list_actions'
import { listAnnotationsTool } from '@/tools/posthog/list_annotations'
import { listCohortsTool } from '@/tools/posthog/list_cohorts'
import { listDashboardsTool } from '@/tools/posthog/list_dashboards'
// Data Management
import { listEventDefinitionsTool } from '@/tools/posthog/list_event_definitions'
import { listExperimentsTool } from '@/tools/posthog/list_experiments'
// Feature Management
import { listFeatureFlagsTool } from '@/tools/posthog/list_feature_flags'
// Analytics
import { listInsightsTool } from '@/tools/posthog/list_insights'
import { listOrganizationsTool } from '@/tools/posthog/list_organizations'
import { listPersonsTool } from '@/tools/posthog/list_persons'
// Configuration
import { listProjectsTool } from '@/tools/posthog/list_projects'
import { listPropertyDefinitionsTool } from '@/tools/posthog/list_property_definitions'
import { listRecordingPlaylistsTool } from '@/tools/posthog/list_recording_playlists'
import { listSessionRecordingsTool } from '@/tools/posthog/list_session_recordings'
// Engagement
import { listSurveysTool } from '@/tools/posthog/list_surveys'
import { queryTool } from '@/tools/posthog/query'
import { updateCohortTool } from '@/tools/posthog/update_cohort'
import { updateEventDefinitionTool } from '@/tools/posthog/update_event_definition'
import { updateExperimentTool } from '@/tools/posthog/update_experiment'
import { updateFeatureFlagTool } from '@/tools/posthog/update_feature_flag'
import { updateInsightTool } from '@/tools/posthog/update_insight'
import { updatePropertyDefinitionTool } from '@/tools/posthog/update_property_definition'
import { updateSurveyTool } from '@/tools/posthog/update_survey'
// Export all tools with posthog prefix
export const posthogCaptureEventTool = captureEventTool
export const posthogBatchEventsTool = batchEventsTool
export const posthogListPersonsTool = listPersonsTool
export const posthogGetPersonTool = getPersonTool
export const posthogDeletePersonTool = deletePersonTool
export const posthogQueryTool = queryTool
export const posthogListInsightsTool = listInsightsTool
export const posthogGetInsightTool = getInsightTool
export const posthogCreateInsightTool = createInsightTool
export const posthogUpdateInsightTool = updateInsightTool
export const posthogListDashboardsTool = listDashboardsTool
export const posthogGetDashboardTool = getDashboardTool
export const posthogCreateDashboardTool = createDashboardTool
export const posthogListActionsTool = listActionsTool
export const posthogListCohortsTool = listCohortsTool
export const posthogGetCohortTool = getCohortTool
export const posthogCreateCohortTool = createCohortTool
export const posthogUpdateCohortTool = updateCohortTool
export const posthogListAnnotationsTool = listAnnotationsTool
export const posthogCreateAnnotationTool = createAnnotationTool
export const posthogListFeatureFlagsTool = listFeatureFlagsTool
export const posthogGetFeatureFlagTool = getFeatureFlagTool
export const posthogCreateFeatureFlagTool = createFeatureFlagTool
export const posthogUpdateFeatureFlagTool = updateFeatureFlagTool
export const posthogDeleteFeatureFlagTool = deleteFeatureFlagTool
export const posthogEvaluateFlagsTool = evaluateFlagsTool
export const posthogListExperimentsTool = listExperimentsTool
export const posthogGetExperimentTool = getExperimentTool
export const posthogCreateExperimentTool = createExperimentTool
export const posthogUpdateExperimentTool = updateExperimentTool
export const posthogListSurveysTool = listSurveysTool
export const posthogGetSurveyTool = getSurveyTool
export const posthogCreateSurveyTool = createSurveyTool
export const posthogUpdateSurveyTool = updateSurveyTool
export const posthogDeleteSurveyTool = deleteSurveyTool
export const posthogListSessionRecordingsTool = listSessionRecordingsTool
export const posthogGetSessionRecordingTool = getSessionRecordingTool
export const posthogListRecordingPlaylistsTool = listRecordingPlaylistsTool
export const posthogListEventDefinitionsTool = listEventDefinitionsTool
export const posthogGetEventDefinitionTool = getEventDefinitionTool
export const posthogUpdateEventDefinitionTool = updateEventDefinitionTool
export const posthogListPropertyDefinitionsTool = listPropertyDefinitionsTool
export const posthogGetPropertyDefinitionTool = getPropertyDefinitionTool
export const posthogUpdatePropertyDefinitionTool = updatePropertyDefinitionTool
export const posthogListProjectsTool = listProjectsTool
export const posthogGetProjectTool = getProjectTool
export const posthogListOrganizationsTool = listOrganizationsTool
export const posthogGetOrganizationTool = getOrganizationTool
+191
View File
@@ -0,0 +1,191 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListActionsParams {
apiKey: string
projectId: string
region: string
host?: string
limit?: number
offset?: number
search?: string
}
interface PostHogListActionsResponse {
success: boolean
output: {
count: number
next: string | null
previous: string | null
results: Array<{
id: number
name: string
description: string
tags: string[]
post_to_slack: boolean
slack_message_format: string
steps: Array<Record<string, any>>
created_at: string
created_by: Record<string, any> | null
deleted: boolean
is_calculating: boolean
last_calculated_at: string
}>
}
}
export const listActionsTool: ToolConfig<PostHogListActionsParams, PostHogListActionsResponse> = {
id: 'posthog_list_actions',
name: 'PostHog List Actions',
description:
'List all actions in a PostHog project. Returns action definitions, steps, and metadata.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter actions by name',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
let url = `${baseUrl}/api/projects/${params.projectId}/actions/`
const queryParams = []
if (params.limit) queryParams.push(`limit=${params.limit}`)
if (params.offset) queryParams.push(`offset=${params.offset}`)
if (params.search) queryParams.push(`search=${encodeURIComponent(params.search)}`)
if (queryParams.length > 0) {
url += `?${queryParams.join('&')}`
}
return url
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
count: data.count || 0,
next: data.next || null,
previous: data.previous || null,
results: (data.results || []).map((action: any) => ({
id: action.id,
name: action.name || '',
description: action.description || '',
tags: action.tags || [],
post_to_slack: action.post_to_slack || false,
slack_message_format: action.slack_message_format || '',
steps: action.steps || [],
created_at: action.created_at,
created_by: action.created_by || null,
deleted: action.deleted || false,
is_calculating: action.is_calculating || false,
last_calculated_at: action.last_calculated_at || '',
})),
},
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of actions in the project',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of actions with their definitions and metadata',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Unique identifier for the action' },
name: { type: 'string', description: 'Name of the action' },
description: { type: 'string', description: 'Description of the action' },
tags: { type: 'array', description: 'Tags associated with the action' },
post_to_slack: {
type: 'boolean',
description: 'Whether to post this action to Slack',
},
slack_message_format: {
type: 'string',
description: 'Format string for Slack messages',
},
steps: { type: 'array', description: 'Steps that define the action' },
created_at: { type: 'string', description: 'ISO timestamp when action was created' },
created_by: { type: 'object', description: 'User who created the action' },
deleted: { type: 'boolean', description: 'Whether the action is deleted' },
is_calculating: {
type: 'boolean',
description: 'Whether the action is being calculated',
},
last_calculated_at: {
type: 'string',
description: 'ISO timestamp of last calculation',
},
},
},
},
},
}
+195
View File
@@ -0,0 +1,195 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListAnnotationsParams {
apiKey: string
projectId: string
region: string
host?: string
limit?: number
offset?: number
}
interface PostHogListAnnotationsResponse {
success: boolean
output: {
count: number
next: string | null
previous: string | null
results: Array<{
id: number
content: string
date_marker: string
created_at: string
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
deleted: boolean
}>
}
}
export const listAnnotationsTool: ToolConfig<
PostHogListAnnotationsParams,
PostHogListAnnotationsResponse
> = {
id: 'posthog_list_annotations',
name: 'PostHog List Annotations',
description:
'List all annotations in a PostHog project. Returns annotation content, timestamps, and associated insights.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
let url = `${baseUrl}/api/projects/${params.projectId}/annotations/`
const queryParams = []
if (params.limit) queryParams.push(`limit=${params.limit}`)
if (params.offset) queryParams.push(`offset=${params.offset}`)
if (queryParams.length > 0) {
url += `?${queryParams.join('&')}`
}
return url
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
count: data.count || 0,
next: data.next || null,
previous: data.previous || null,
results: (data.results || []).map((annotation: any) => ({
id: annotation.id,
content: annotation.content || '',
date_marker: annotation.date_marker,
created_at: annotation.created_at,
updated_at: annotation.updated_at,
created_by: annotation.created_by || null,
dashboard_item: annotation.dashboard_item || null,
dashboard_id: annotation.dashboard_id || null,
insight_short_id: annotation.insight_short_id || null,
insight_name: annotation.insight_name || null,
scope: annotation.scope || '',
deleted: annotation.deleted || false,
})),
},
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of annotations in the project',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of annotations with their content and metadata',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Unique identifier for the annotation' },
content: { type: 'string', description: 'Content/text of the annotation' },
date_marker: {
type: 'string',
description: 'ISO timestamp marking when the annotation applies',
},
created_at: {
type: 'string',
description: 'ISO timestamp when annotation was created',
},
updated_at: {
type: 'string',
description: 'ISO timestamp when annotation was last updated',
},
created_by: { type: 'object', description: 'User who created the annotation' },
dashboard_item: {
type: 'number',
description: 'ID of dashboard item this annotation is attached to',
},
dashboard_id: {
type: 'number',
description: 'ID of the dashboard this annotation is attached to',
},
insight_short_id: {
type: 'string',
description: 'Short ID of the insight this annotation is attached to',
},
insight_name: {
type: 'string',
description: 'Name of the insight this annotation is attached to',
},
scope: { type: 'string', description: 'Scope of the annotation (project or dashboard)' },
deleted: { type: 'boolean', description: 'Whether the annotation is deleted' },
},
},
},
},
}
+186
View File
@@ -0,0 +1,186 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListCohortsParams {
apiKey: string
projectId: string
region: string
host?: string
limit?: number
offset?: number
}
interface PostHogListCohortsResponse {
success: boolean
output: {
count: number
next: string | null
previous: string | null
results: Array<{
id: number
name: string
description: string
groups: Array<Record<string, any>>
deleted: boolean
filters: Record<string, any>
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
is_calculating: boolean
last_calculation: string
errors_calculating: number
count: number
is_static: boolean
}>
}
}
export const listCohortsTool: ToolConfig<PostHogListCohortsParams, PostHogListCohortsResponse> = {
id: 'posthog_list_cohorts',
name: 'PostHog List Cohorts',
description:
'List all cohorts in a PostHog project. Returns cohort definitions, filters, and user counts.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
let url = `${baseUrl}/api/projects/${params.projectId}/cohorts/`
const queryParams = []
if (params.limit) queryParams.push(`limit=${params.limit}`)
if (params.offset) queryParams.push(`offset=${params.offset}`)
if (queryParams.length > 0) {
url += `?${queryParams.join('&')}`
}
return url
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
count: data.count || 0,
next: data.next || null,
previous: data.previous || null,
results: (data.results || []).map((cohort: any) => ({
id: cohort.id,
name: cohort.name || '',
description: cohort.description || '',
groups: cohort.groups || [],
deleted: cohort.deleted || false,
filters: cohort.filters || {},
query: cohort.query || null,
created_at: cohort.created_at,
created_by: cohort.created_by || null,
is_calculating: cohort.is_calculating || false,
last_calculation: cohort.last_calculation || '',
errors_calculating: cohort.errors_calculating || 0,
count: cohort.count || 0,
is_static: cohort.is_static || false,
})),
},
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of cohorts in the project',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of cohorts with their definitions and metadata',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Unique identifier for the cohort' },
name: { type: 'string', description: 'Name of the cohort' },
description: { type: 'string', description: 'Description of the cohort' },
groups: { type: 'array', description: 'Groups that define the cohort' },
deleted: { type: 'boolean', description: 'Whether the cohort is deleted' },
filters: { type: 'object', description: 'Filter configuration for the cohort' },
query: { type: 'object', description: 'Query configuration for the cohort' },
created_at: { type: 'string', description: 'ISO timestamp when cohort was created' },
created_by: { type: 'object', description: 'User who created the cohort' },
is_calculating: {
type: 'boolean',
description: 'Whether the cohort is being calculated',
},
last_calculation: {
type: 'string',
description: 'ISO timestamp of last calculation',
},
errors_calculating: {
type: 'number',
description: 'Number of errors during calculation',
},
count: { type: 'number', description: 'Number of users in the cohort' },
is_static: { type: 'boolean', description: 'Whether the cohort is static' },
},
},
},
},
}
+177
View File
@@ -0,0 +1,177 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListDashboardsParams {
apiKey: string
projectId: string
region: string
host?: string
limit?: number
offset?: number
}
interface PostHogListDashboardsResponse {
success: boolean
output: {
count: number
next: string | null
previous: string | null
results: Array<{
id: number
name: string
description: string
pinned: boolean
created_at: string
created_by: Record<string, any> | null
last_modified_at: string
last_modified_by: Record<string, any> | null
tiles: Array<Record<string, any>>
filters: Record<string, any>
tags: string[]
}>
}
}
export const listDashboardsTool: ToolConfig<
PostHogListDashboardsParams,
PostHogListDashboardsResponse
> = {
id: 'posthog_list_dashboards',
name: 'PostHog List Dashboards',
description:
'List all dashboards in a PostHog project. Returns dashboard configurations, tiles, and metadata.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
let url = `${baseUrl}/api/projects/${params.projectId}/dashboards/`
const queryParams = []
if (params.limit) queryParams.push(`limit=${params.limit}`)
if (params.offset) queryParams.push(`offset=${params.offset}`)
if (queryParams.length > 0) {
url += `?${queryParams.join('&')}`
}
return url
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
count: data.count || 0,
next: data.next || null,
previous: data.previous || null,
results: (data.results || []).map((dashboard: any) => ({
id: dashboard.id,
name: dashboard.name || '',
description: dashboard.description || '',
pinned: dashboard.pinned || false,
created_at: dashboard.created_at,
created_by: dashboard.created_by || null,
last_modified_at: dashboard.last_modified_at,
last_modified_by: dashboard.last_modified_by || null,
tiles: dashboard.tiles || [],
filters: dashboard.filters || {},
tags: dashboard.tags || [],
})),
},
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of dashboards in the project',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of dashboards with their configurations and metadata',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Unique identifier for the dashboard' },
name: { type: 'string', description: 'Name of the dashboard' },
description: { type: 'string', description: 'Description of the dashboard' },
pinned: { type: 'boolean', description: 'Whether the dashboard is pinned' },
created_at: { type: 'string', description: 'ISO timestamp when dashboard was created' },
created_by: { type: 'object', description: 'User who created the dashboard' },
last_modified_at: {
type: 'string',
description: 'ISO timestamp when dashboard was last modified',
},
last_modified_by: {
type: 'object',
description: 'User who last modified the dashboard',
},
tiles: { type: 'array', description: 'Tiles/widgets on the dashboard' },
filters: { type: 'object', description: 'Global filters for the dashboard' },
tags: { type: 'array', description: 'Tags associated with the dashboard' },
},
},
},
},
}
@@ -0,0 +1,175 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListEventDefinitionsParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
limit?: number
offset?: number
search?: string
}
interface EventDefinition {
id: string
name: string
description: string
tags: string[]
created_at: string
last_seen_at: string | null
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
}
interface PostHogListEventDefinitionsResponse {
count: number
next: string | null
previous: string | null
results: EventDefinition[]
}
export const listEventDefinitionsTool: ToolConfig<
PostHogListEventDefinitionsParams,
PostHogListEventDefinitionsResponse
> = {
id: 'posthog_list_event_definitions',
name: 'PostHog List Event Definitions',
description:
'List all event definitions in a PostHog project. Event definitions represent tracked events with metadata like descriptions, tags, and usage statistics.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The initial index from which to return results (e.g., 0, 100, 200)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter event definitions by name',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit.toString())
if (params.offset) queryParams.append('offset', params.offset.toString())
if (params.search) queryParams.append('search', params.search)
const query = queryParams.toString()
return `${baseUrl}/api/projects/${params.projectId}/event_definitions/${query ? `?${query}` : ''}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
count: data.count,
next: data.next ?? null,
previous: data.previous ?? null,
results: data.results.map((event: any) => ({
id: event.id,
name: event.name,
description: event.description || '',
tags: event.tags || [],
created_at: event.created_at,
last_seen_at: event.last_seen_at ?? null,
updated_at: event.updated_at,
updated_by: event.updated_by ?? null,
})),
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of event definitions',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of event definitions',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique identifier for the event definition' },
name: { type: 'string', description: 'Event name' },
description: { type: 'string', description: 'Event description' },
tags: { type: 'array', description: 'Tags associated with the event' },
created_at: { type: 'string', description: 'ISO timestamp when the event was created' },
last_seen_at: {
type: 'string',
description: 'ISO timestamp when the event was last seen',
optional: true,
},
updated_at: { type: 'string', description: 'ISO timestamp when the event was updated' },
updated_by: {
type: 'object',
description: 'User who last updated the event',
optional: true,
},
},
},
},
},
}
+147
View File
@@ -0,0 +1,147 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface ListExperimentsParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
limit?: number
offset?: number
}
interface Experiment {
id: number
name: string
description: string
feature_flag_key: string
feature_flag: Record<string, any>
parameters: Record<string, any>
filters: Record<string, any>
start_date: string | null
end_date: string | null
created_at: string
created_by: Record<string, any>
archived: boolean
}
interface ListExperimentsResponse {
results: Experiment[]
count: number
next: string | null
previous: string | null
}
export const listExperimentsTool: ToolConfig<ListExperimentsParams, ListExperimentsResponse> = {
id: 'posthog_list_experiments',
name: 'PostHog List Experiments',
description: 'List all experiments in a PostHog project',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(`${baseUrl}/api/projects/${params.projectId}/experiments/`)
if (params.limit) url.searchParams.append('limit', String(params.limit))
if (params.offset) url.searchParams.append('offset', String(params.offset))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
results: data.results,
count: data.count,
next: data.next ?? null,
previous: data.previous ?? null,
}
},
outputs: {
results: {
type: 'array',
description: 'List of experiments',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Experiment ID' },
name: { type: 'string', description: 'Experiment name' },
description: { type: 'string', description: 'Experiment description' },
feature_flag_key: { type: 'string', description: 'Associated feature flag key' },
feature_flag: { type: 'object', description: 'Feature flag details' },
parameters: { type: 'object', description: 'Experiment parameters' },
filters: { type: 'object', description: 'Experiment filters' },
start_date: { type: 'string', description: 'Start date', optional: true },
end_date: { type: 'string', description: 'End date', optional: true },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
archived: { type: 'boolean', description: 'Whether the experiment is archived' },
},
},
},
count: {
type: 'number',
description: 'Total number of experiments',
},
next: {
type: 'string',
description: 'URL to next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL to previous page of results',
optional: true,
},
},
}
@@ -0,0 +1,152 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface ListFeatureFlagsParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
limit?: number
offset?: number
}
interface FeatureFlag {
id: number
name: string
key: string
filters: Record<string, any>
deleted: boolean
active: boolean
created_at: string
created_by: Record<string, any>
is_simple_flag: boolean
rollout_percentage: number | null
ensure_experience_continuity: boolean
}
interface ListFeatureFlagsResponse {
results: FeatureFlag[]
count: number
next: string | null
previous: string | null
}
export const listFeatureFlagsTool: ToolConfig<ListFeatureFlagsParams, ListFeatureFlagsResponse> = {
id: 'posthog_list_feature_flags',
name: 'PostHog List Feature Flags',
description: 'List all feature flags in a PostHog project',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(`${baseUrl}/api/projects/${params.projectId}/feature_flags/`)
if (params.limit) url.searchParams.append('limit', String(params.limit))
if (params.offset) url.searchParams.append('offset', String(params.offset))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
results: data.results,
count: data.count,
next: data.next ?? null,
previous: data.previous ?? null,
}
},
outputs: {
results: {
type: 'array',
description: 'List of feature flags',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Feature flag ID' },
name: { type: 'string', description: 'Feature flag name' },
key: { type: 'string', description: 'Feature flag key' },
filters: { type: 'object', description: 'Feature flag filters' },
deleted: { type: 'boolean', description: 'Whether the flag is deleted' },
active: { type: 'boolean', description: 'Whether the flag is active' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
is_simple_flag: { type: 'boolean', description: 'Whether this is a simple flag' },
rollout_percentage: {
type: 'number',
description: 'Rollout percentage (if applicable)',
optional: true,
},
ensure_experience_continuity: {
type: 'boolean',
description: 'Whether to ensure experience continuity',
},
},
},
},
count: {
type: 'number',
description: 'Total number of feature flags',
},
next: {
type: 'string',
description: 'URL to next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL to previous page of results',
optional: true,
},
},
}
+169
View File
@@ -0,0 +1,169 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListInsightsParams {
apiKey: string
projectId: string
region: string
host?: string
limit?: number
offset?: number
}
interface PostHogListInsightsResponse {
success: boolean
output: {
count: number
next: string | null
previous: string | null
results: Array<{
id: number
name: string
description: string
query: Record<string, any> | null
created_at: string
created_by: Record<string, any> | null
last_modified_at: string
last_modified_by: Record<string, any> | null
dashboards: number[]
}>
}
}
export const listInsightsTool: ToolConfig<PostHogListInsightsParams, PostHogListInsightsResponse> =
{
id: 'posthog_list_insights',
name: 'PostHog List Insights',
description:
'List all insights in a PostHog project. Returns insight configurations and metadata.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region as 'us' | 'eu' | undefined, params.host)
let url = `${baseUrl}/api/projects/${params.projectId}/insights/`
const queryParams = []
if (params.limit) queryParams.push(`limit=${params.limit}`)
if (params.offset) queryParams.push(`offset=${params.offset}`)
if (queryParams.length > 0) {
url += `?${queryParams.join('&')}`
}
return url
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
count: data.count || 0,
next: data.next || null,
previous: data.previous || null,
results: (data.results || []).map((insight: any) => ({
id: insight.id,
name: insight.name || '',
description: insight.description || '',
query: insight.query || null,
created_at: insight.created_at,
created_by: insight.created_by || null,
last_modified_at: insight.last_modified_at,
last_modified_by: insight.last_modified_by || null,
dashboards: insight.dashboards || [],
})),
},
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of insights in the project',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of insights with their configurations and metadata',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Unique identifier for the insight' },
name: { type: 'string', description: 'Name of the insight' },
description: { type: 'string', description: 'Description of the insight' },
query: { type: 'object', description: 'Query configuration for the insight' },
created_at: { type: 'string', description: 'ISO timestamp when insight was created' },
created_by: { type: 'object', description: 'User who created the insight' },
last_modified_at: {
type: 'string',
description: 'ISO timestamp when insight was last modified',
},
last_modified_by: { type: 'object', description: 'User who last modified the insight' },
dashboards: {
type: 'array',
description: 'IDs of dashboards this insight appears on',
},
},
},
},
},
}
@@ -0,0 +1,132 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogListOrganizationsParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogOrganization {
id: string
name: string
slug: string
created_at: string
updated_at: string
membership_level: number
plugins_access_level: number
teams: number[]
available_product_features: Array<{
key: string
name: string
description: string
unit: string
limit: number | null
note: string | null
}>
}
export interface PostHogListOrganizationsResponse {
success: boolean
output: {
organizations: PostHogOrganization[]
}
error?: string
}
export const listOrganizationsTool: ToolConfig<
PostHogListOrganizationsParams,
PostHogListOrganizationsResponse
> = {
id: 'posthog_list_organizations',
name: 'PostHog List Organizations',
description:
'List all organizations the user has access to. Returns organization details including name, slug, membership level, and available product features.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cloud region: us 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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/organizations/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
organizations: (data.results || []).map((org: any) => ({
id: org.id,
name: org.name,
slug: org.slug,
created_at: org.created_at,
updated_at: org.updated_at,
membership_level: org.membership_level,
plugins_access_level: org.plugins_access_level,
teams: org.teams || [],
available_product_features: org.available_product_features || [],
})),
},
}
},
outputs: {
organizations: {
type: 'array',
description: 'List of organizations with their settings and features',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Organization ID (UUID)' },
name: { type: 'string', description: 'Organization name' },
slug: { type: 'string', description: 'Organization slug' },
created_at: { type: 'string', description: 'Organization creation timestamp' },
updated_at: { type: 'string', description: 'Last update timestamp' },
membership_level: {
type: 'number',
description: 'User membership level in organization',
},
plugins_access_level: {
type: 'number',
description: 'Access level for plugins/apps',
},
teams: { type: 'array', description: 'List of team IDs in this organization' },
available_product_features: {
type: 'array',
description: 'Available product features and their limits',
},
},
},
},
},
}
+158
View File
@@ -0,0 +1,158 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogListPersonsParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
projectId: string
limit?: number
offset?: number
search?: string
distinctId?: string
}
interface PostHogPerson {
id: string
name: string
distinct_ids: string[]
properties: Record<string, any>
created_at: string
uuid: string
}
export interface PostHogListPersonsResponse {
success: boolean
output: {
persons: PostHogPerson[]
next?: string
}
}
export const listPersonsTool: ToolConfig<PostHogListPersonsParams, PostHogListPersonsResponse> = {
id: 'posthog_list_persons',
name: 'PostHog List Persons',
description:
'List persons (users) in PostHog. Returns user profiles with their properties and distinct IDs.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key (for authenticated API access)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of persons to return (default: 100, max: 100)',
default: 100,
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of persons to skip for pagination (e.g., 0, 100, 200)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search persons by email, name, or distinct ID',
},
distinctId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by specific distinct_id',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(`${baseUrl}/api/projects/${params.projectId}/persons/`)
if (params.limit) url.searchParams.append('limit', params.limit.toString())
if (params.offset) url.searchParams.append('offset', params.offset.toString())
if (params.search) url.searchParams.append('search', params.search)
if (params.distinctId) url.searchParams.append('distinct_id', params.distinctId)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
persons:
data.results?.map((person: any) => ({
id: person.id,
name: person.name || '',
distinct_ids: person.distinct_ids || [],
properties: person.properties || {},
created_at: person.created_at,
uuid: person.uuid,
})) || [],
next: data.next || undefined,
},
}
},
outputs: {
persons: {
type: 'array',
description: 'List of persons with their properties and identifiers',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Person ID' },
name: { type: 'string', description: 'Person name' },
distinct_ids: {
type: 'array',
description: 'All distinct IDs associated with this person',
},
properties: { type: 'object', description: 'Person properties' },
created_at: { type: 'string', description: 'When the person was first seen' },
uuid: { type: 'string', description: 'Person UUID' },
},
},
},
next: {
type: 'string',
description: 'URL for the next page of results (if available)',
optional: true,
},
},
}
+141
View File
@@ -0,0 +1,141 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogListProjectsParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
}
interface PostHogProject {
id: number
uuid: string
organization: string
api_token: string
app_urls: string[]
name: string
slack_incoming_webhook: string
created_at: string
updated_at: string
anonymize_ips: boolean
completed_snippet_onboarding: boolean
ingested_event: boolean
test_account_filters: any[]
is_demo: boolean
timezone: string
data_attributes: string[]
}
export interface PostHogListProjectsResponse {
success: boolean
output: {
projects: PostHogProject[]
}
error?: string
}
export const listProjectsTool: ToolConfig<PostHogListProjectsParams, PostHogListProjectsResponse> =
{
id: 'posthog_list_projects',
name: 'PostHog List Projects',
description:
'List all projects in the organization. Returns project details including IDs, names, API tokens, and settings. Useful for getting project IDs needed by other endpoints.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Cloud region: us 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.',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
projects: (data.results || []).map((project: any) => ({
id: project.id,
uuid: project.uuid,
organization: project.organization,
api_token: project.api_token,
app_urls: project.app_urls || [],
name: project.name,
slack_incoming_webhook: project.slack_incoming_webhook,
created_at: project.created_at,
updated_at: project.updated_at,
anonymize_ips: project.anonymize_ips,
completed_snippet_onboarding: project.completed_snippet_onboarding,
ingested_event: project.ingested_event,
test_account_filters: project.test_account_filters || [],
is_demo: project.is_demo,
timezone: project.timezone,
data_attributes: project.data_attributes || [],
})),
},
}
},
outputs: {
projects: {
type: 'array',
description: 'List of projects with their configuration and settings',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Project ID' },
uuid: { type: 'string', description: 'Project UUID' },
organization: { type: 'string', description: 'Organization UUID' },
api_token: { type: 'string', description: 'Project API token for ingestion' },
app_urls: { type: 'array', description: 'Allowed app URLs' },
name: { type: 'string', description: 'Project name' },
slack_incoming_webhook: {
type: 'string',
description: 'Slack webhook URL for notifications',
},
created_at: { type: 'string', description: 'Project creation timestamp' },
updated_at: { type: 'string', description: 'Last update timestamp' },
anonymize_ips: { type: 'boolean', description: 'Whether IP anonymization is enabled' },
completed_snippet_onboarding: {
type: 'boolean',
description: 'Whether snippet onboarding is completed',
},
ingested_event: { type: 'boolean', description: 'Whether any event has been ingested' },
test_account_filters: { type: 'array', description: 'Filters for test accounts' },
is_demo: { type: 'boolean', description: 'Whether this is a demo project' },
timezone: { type: 'string', description: 'Project timezone' },
data_attributes: { type: 'array', description: 'Custom data attributes' },
},
},
},
},
}
@@ -0,0 +1,198 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListPropertyDefinitionsParams {
projectId: string
region: 'us' | 'eu'
host?: string
apiKey: string
limit?: number
offset?: number
search?: string
type?: 'event' | 'person' | 'group' | 'session'
}
interface PropertyDefinition {
id: string
name: string
description: string
tags: string[]
is_numerical: boolean
is_seen_on_filtered_events: boolean | null
property_type: string
type: 'event' | 'person' | 'group' | 'session'
created_at: string
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
}
interface PostHogListPropertyDefinitionsResponse {
count: number
next: string | null
previous: string | null
results: PropertyDefinition[]
}
export const listPropertyDefinitionsTool: ToolConfig<
PostHogListPropertyDefinitionsParams,
PostHogListPropertyDefinitionsResponse
> = {
id: 'posthog_list_property_definitions',
name: 'PostHog List Property Definitions',
description:
'List all property definitions in a PostHog project. Property definitions represent tracked properties with metadata like descriptions, tags, types, and usage statistics.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return per page (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The initial index from which to return results (e.g., 0, 100, 200)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter property definitions by name',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by property type: event, person, or group',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit.toString())
if (params.offset) queryParams.append('offset', params.offset.toString())
if (params.search) queryParams.append('search', params.search)
if (params.type) queryParams.append('type', params.type)
const query = queryParams.toString()
return `${baseUrl}/api/projects/${params.projectId}/property_definitions/${query ? `?${query}` : ''}`
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
count: data.count,
next: data.next ?? null,
previous: data.previous ?? null,
results: data.results.map((property: any) => ({
id: property.id,
name: property.name,
description: property.description || '',
tags: property.tags || [],
is_numerical: property.is_numerical || false,
is_seen_on_filtered_events: property.is_seen_on_filtered_events ?? null,
property_type: property.property_type,
type: property.type,
created_at: property.created_at,
updated_at: property.updated_at,
updated_by: property.updated_by ?? null,
})),
}
},
outputs: {
count: {
type: 'number',
description: 'Total number of property definitions',
},
next: {
type: 'string',
description: 'URL for the next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for the previous page of results',
optional: true,
},
results: {
type: 'array',
description: 'List of property definitions',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique identifier for the property definition' },
name: { type: 'string', description: 'Property name' },
description: { type: 'string', description: 'Property description' },
tags: { type: 'array', description: 'Tags associated with the property' },
is_numerical: { type: 'boolean', description: 'Whether the property is numerical' },
is_seen_on_filtered_events: {
type: 'boolean',
description: 'Whether the property is seen on filtered events',
optional: true,
},
property_type: { type: 'string', description: 'The data type of the property' },
type: { type: 'string', description: 'Property type: event, person, group, or session' },
created_at: {
type: 'string',
description: 'ISO timestamp when the property was created',
},
updated_at: {
type: 'string',
description: 'ISO timestamp when the property was updated',
},
updated_by: {
type: 'object',
description: 'User who last updated the property',
optional: true,
},
},
},
},
},
}
@@ -0,0 +1,168 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListRecordingPlaylistsParams {
apiKey: string
projectId: string
region?: 'us' | 'eu'
host?: string
limit?: number
offset?: number
}
interface PostHogRecordingPlaylist {
id: string
short_id: string
name: string
description?: string
created_at: string
created_by: {
id: string
uuid: string
distinct_id: string
first_name: string
email: string
}
deleted: boolean
filters?: Record<string, any>
last_modified_at: string
last_modified_by: Record<string, any>
derived_name?: string
}
interface PostHogListRecordingPlaylistsResponse {
success: boolean
output: {
playlists: PostHogRecordingPlaylist[]
count: number
next?: string
previous?: string
}
}
export const listRecordingPlaylistsTool: ToolConfig<
PostHogListRecordingPlaylistsParams,
PostHogListRecordingPlaylistsResponse
> = {
id: 'posthog_list_recording_playlists',
name: 'PostHog List Recording Playlists',
description:
'List session recording playlists in a PostHog project. Playlists allow you to organize and curate session recordings.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(
`${baseUrl}/api/projects/${params.projectId}/session_recording_playlists/`
)
if (params.limit) {
url.searchParams.set('limit', params.limit.toString())
}
if (params.offset) {
url.searchParams.set('offset', params.offset.toString())
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
playlists: data.results || [],
count: data.count || 0,
next: data.next ?? null,
previous: data.previous ?? null,
},
}
},
outputs: {
playlists: {
type: 'array',
description: 'List of session recording playlists',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Playlist ID' },
short_id: { type: 'string', description: 'Playlist short ID' },
name: { type: 'string', description: 'Playlist name' },
description: { type: 'string', description: 'Playlist description' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
deleted: { type: 'boolean', description: 'Whether playlist is deleted' },
filters: { type: 'object', description: 'Playlist filters' },
last_modified_at: { type: 'string', description: 'Last modification timestamp' },
last_modified_by: { type: 'object', description: 'Last modifier information' },
derived_name: { type: 'string', description: 'Auto-generated name from filters' },
},
},
},
count: {
type: 'number',
description: 'Total number of playlists',
},
next: {
type: 'string',
description: 'URL for next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for previous page of results',
optional: true,
},
},
}
@@ -0,0 +1,170 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListSessionRecordingsParams {
apiKey: string
projectId: string
region?: 'us' | 'eu'
host?: string
limit?: number
offset?: number
}
interface PostHogSessionRecording {
id: string
distinct_id: string
viewed: boolean
recording_duration: number
active_seconds: number
inactive_seconds: number
start_time: string
end_time: string
click_count: number
keypress_count: number
console_log_count: number
console_warn_count: number
console_error_count: number
person?: {
id: string
name?: string
properties?: Record<string, any>
}
}
interface PostHogListSessionRecordingsResponse {
success: boolean
output: {
recordings: PostHogSessionRecording[]
count: number
next?: string
previous?: string
}
}
export const listSessionRecordingsTool: ToolConfig<
PostHogListSessionRecordingsParams,
PostHogListSessionRecordingsResponse
> = {
id: 'posthog_list_session_recordings',
name: 'PostHog List Session Recordings',
description:
'List session recordings in a PostHog project. Session recordings capture user interactions with your application.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (default: 50, e.g., 10, 25, 50)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 50, 100)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(`${baseUrl}/api/projects/${params.projectId}/session_recordings/`)
if (params.limit) {
url.searchParams.set('limit', params.limit.toString())
}
if (params.offset) {
url.searchParams.set('offset', params.offset.toString())
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
recordings: data.results || [],
count: data.count || 0,
next: data.next ?? null,
previous: data.previous ?? null,
},
}
},
outputs: {
recordings: {
type: 'array',
description: 'List of session recordings',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Recording ID' },
distinct_id: { type: 'string', description: 'User distinct ID' },
viewed: { type: 'boolean', description: 'Whether recording has been viewed' },
recording_duration: { type: 'number', description: 'Recording duration in seconds' },
active_seconds: { type: 'number', description: 'Active time in seconds' },
inactive_seconds: { type: 'number', description: 'Inactive time in seconds' },
start_time: { type: 'string', description: 'Recording start timestamp' },
end_time: { type: 'string', description: 'Recording end timestamp' },
click_count: { type: 'number', description: 'Number of clicks' },
keypress_count: { type: 'number', description: 'Number of keypresses' },
console_log_count: { type: 'number', description: 'Number of console logs' },
console_warn_count: { type: 'number', description: 'Number of console warnings' },
console_error_count: { type: 'number', description: 'Number of console errors' },
person: { type: 'object', description: 'Person information' },
},
},
},
count: {
type: 'number',
description: 'Total number of recordings',
},
next: {
type: 'string',
description: 'URL for next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for previous page of results',
optional: true,
},
},
}
+165
View File
@@ -0,0 +1,165 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogListSurveysParams {
apiKey: string
projectId: string
region?: 'us' | 'eu'
host?: string
limit?: number
offset?: number
}
interface PostHogSurvey {
id: string
name: string
description: string
type: 'popover' | 'api'
questions: Array<{
type: 'open' | 'link' | 'rating' | 'multiple_choice'
question: string
description?: string
choices?: string[]
scale?: number
}>
appearance?: Record<string, any>
conditions?: Record<string, any>
created_at: string
created_by: Record<string, any>
start_date?: string
end_date?: string
archived?: boolean
}
interface PostHogListSurveysResponse {
success: boolean
output: {
surveys: PostHogSurvey[]
count: number
next?: string
previous?: string
}
}
export const listSurveysTool: ToolConfig<PostHogListSurveysParams, PostHogListSurveysResponse> = {
id: 'posthog_list_surveys',
name: 'PostHog List Surveys',
description:
'List all surveys in a PostHog project. Surveys allow you to collect feedback from users.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (default: 100, e.g., 10, 50, 100)',
},
offset: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to skip for pagination (e.g., 0, 100, 200)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
const url = new URL(`${baseUrl}/api/projects/${params.projectId}/surveys/`)
if (params.limit) {
url.searchParams.set('limit', params.limit.toString())
}
if (params.offset) {
url.searchParams.set('offset', params.offset.toString())
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
surveys: data.results || [],
count: data.count || 0,
next: data.next ?? null,
previous: data.previous ?? null,
},
}
},
outputs: {
surveys: {
type: 'array',
description: 'List of surveys in the project',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Survey ID' },
name: { type: 'string', description: 'Survey name' },
description: { type: 'string', description: 'Survey description' },
type: { type: 'string', description: 'Survey type (popover or api)' },
questions: {
type: 'array',
description: 'Survey questions',
},
created_at: { type: 'string', description: 'Creation timestamp' },
start_date: { type: 'string', description: 'Survey start date' },
end_date: { type: 'string', description: 'Survey end date' },
archived: { type: 'boolean', description: 'Whether survey is archived' },
},
},
},
count: {
type: 'number',
description: 'Total number of surveys',
},
next: {
type: 'string',
description: 'URL for next page of results',
optional: true,
},
previous: {
type: 'string',
description: 'URL for previous page of results',
optional: true,
},
},
}
+164
View File
@@ -0,0 +1,164 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
export interface PostHogQueryParams {
apiKey: string
region?: 'us' | 'eu'
host?: string
projectId: string
query: string
values?: string
}
export interface PostHogQueryResponse {
success: boolean
output: {
results: any[]
columns?: string[]
types?: string[]
hogql?: string
has_more?: boolean
}
}
export const queryTool: ToolConfig<PostHogQueryParams, PostHogQueryResponse> = {
id: 'posthog_query',
name: 'PostHog Query',
description:
"Execute a HogQL query in PostHog. HogQL is PostHog's SQL-like query language for analytics. Use this for advanced data retrieval and analysis.",
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key (for authenticated API access)',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'HogQL query to execute. Example: {"kind": "HogQLQuery", "query": "SELECT event, count() FROM events WHERE timestamp > now() - INTERVAL 1 DAY GROUP BY event"}',
},
values: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Optional JSON string of parameter values for parameterized queries. Example: {"user_id": "123"}',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/query/`
},
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
let query: any
try {
query = JSON.parse(params.query)
} catch (e) {
// If it's not valid JSON, treat it as a raw HogQL string
query = {
kind: 'HogQLQuery',
query: params.query,
}
}
const body: Record<string, any> = {
query: query,
}
if (params.values) {
try {
body.values = JSON.parse(params.values)
} catch (e) {
// Ignore invalid values JSON
}
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
results: data.results || [],
columns: data.columns || undefined,
types: data.types || undefined,
hogql: data.hogql || undefined,
has_more: data.hasMore || false,
},
}
},
outputs: {
results: {
type: 'array',
description: 'Query results as an array of rows',
items: {
type: 'object',
properties: {},
},
},
columns: {
type: 'array',
description: 'Column names in the result set',
optional: true,
items: {
type: 'string',
},
},
types: {
type: 'array',
description: 'Data types of columns in the result set',
optional: true,
items: {
type: 'string',
},
},
hogql: {
type: 'string',
description: 'The actual HogQL query that was executed',
optional: true,
},
has_more: {
type: 'boolean',
description: 'Whether there are more results available',
optional: true,
},
},
}
+206
View File
@@ -0,0 +1,206 @@
// Common types for PostHog tools
import type { ToolResponse } from '@/tools/types'
// Common base parameters
interface PostHogBaseParams {
region?: 'us' | 'eu'
}
interface PostHogPublicParams extends PostHogBaseParams {
projectApiKey: string
}
interface PostHogPrivateParams extends PostHogBaseParams {
apiKey: string
projectId: string
}
// Common data types
interface PostHogPerson {
id: string
name: string
distinct_ids: string[]
properties: Record<string, any>
created_at: string
uuid: string
}
interface PostHogEvent {
id: string
distinct_id: string
properties: Record<string, any>
event: string
timestamp: string
person?: PostHogPerson
}
interface PostHogFeatureFlag {
id: number
name: string
key: string
filters: Record<string, any>
deleted: boolean
active: boolean
created_at: string
created_by: any
is_simple_flag: boolean
rollout_percentage?: number
ensure_experience_continuity?: boolean
}
interface PostHogInsight {
id: number
name: string
description: string
favorited: boolean
filters: Record<string, any>
query?: Record<string, any>
result?: any
created_at: string
created_by: any
last_modified_at: string
last_modified_by: any
deleted: boolean
saved: boolean
short_id: string
}
interface PostHogDashboard {
id: number
name: string
description: string
pinned: boolean
created_at: string
created_by: any
is_shared: boolean
deleted: boolean
creation_mode: string
restriction_level: number
filters: Record<string, any>
tiles: any[]
}
interface PostHogCohort {
id: number
name: string
description: string
groups: any[]
filters?: Record<string, any>
query?: Record<string, any>
is_calculating: boolean
count?: number
created_at: string
created_by: any
deleted: boolean
is_static: boolean
version?: number
}
interface PostHogExperiment {
id: number
name: string
description: string
feature_flag_key: string
feature_flag: any
parameters: Record<string, any>
filters: Record<string, any>
start_date?: string
end_date?: string
created_at: string
created_by: any
archived: boolean
}
interface PostHogSurvey {
id: string
name: string
description: string
type: 'popover' | 'api'
questions: any[]
appearance?: Record<string, any>
conditions?: Record<string, any>
start_date?: string
end_date?: string
archived: boolean
created_at: string
created_by: any
}
interface PostHogSessionRecording {
id: string
distinct_id: string
viewed: boolean
recording_duration: number
start_time: string
end_time: string
click_count: number
keypress_count: number
console_error_count: number
console_warn_count: number
console_log_count: number
person?: PostHogPerson
}
interface PostHogAnnotation {
id: number
content: string
date_marker: string
created_at: string
updated_at: string
created_by: any
dashboard_item?: number
scope: string
deleted: boolean
}
interface PostHogEventDefinition {
id: string
name: string
description: string
tags: string[]
created_at: string
last_seen_at?: string
verified: boolean
}
interface PostHogPropertyDefinition {
id: string
name: string
description: string
tags: string[]
is_numerical: boolean
property_type: 'DateTime' | 'String' | 'Numeric' | 'Boolean'
verified: boolean
}
interface PostHogProject {
id: number
uuid: string
organization: string
api_token: string
app_urls: string[]
name: string
slack_incoming_webhook?: string
created_at: string
updated_at: string
anonymize_ips: boolean
completed_snippet_onboarding: boolean
ingested_event: boolean
test_account_filters: any[]
is_demo: boolean
}
interface PostHogOrganization {
id: string
name: string
created_at: string
updated_at: string
membership_level?: number
personalization?: Record<string, any>
setup?: Record<string, any>
available_features: string[]
is_member_join_email_enabled: boolean
}
// Union type for all PostHog responses
export type PostHogResponse = ToolResponse
+245
View File
@@ -0,0 +1,245 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogUpdateCohortParams {
apiKey: string
projectId: string
cohortId: string
region?: 'us' | 'eu'
host?: string
name?: string
description?: string
filters?: string
query?: string
isStatic?: boolean
groups?: string
deleted?: boolean
}
interface PostHogUpdateCohortResponse {
success: boolean
output: {
id: number
name: string
description: string
groups: Array<Record<string, any>>
deleted: boolean
filters: Record<string, any>
query: Record<string, any> | null
created_at: string
is_calculating: boolean
count: number
is_static: boolean
version: number
}
}
export const updateCohortTool: ToolConfig<PostHogUpdateCohortParams, PostHogUpdateCohortResponse> =
{
id: 'posthog_update_cohort',
name: 'PostHog Update Cohort',
description:
'Update an existing cohort in PostHog. Can modify name, description, filters, query, static membership, and deleted status.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
cohortId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The cohort ID to update (e.g., "42")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description: 'Updated name for the cohort',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated description of the cohort',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of updated filter configuration for the cohort',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of updated query configuration for the cohort',
},
isStatic: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the cohort is static',
},
groups: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of updated groups that define the cohort',
},
deleted: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Set to true to archive (soft-delete) the cohort',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/cohorts/${params.cohortId}/`
},
method: 'PATCH',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name !== undefined) body.name = params.name
if (params.description !== undefined) body.description = params.description
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (error) {
throw new Error(`Invalid filters JSON: ${getErrorMessage(error)}`)
}
}
if (params.query) {
try {
body.query = JSON.parse(params.query)
} catch (error) {
throw new Error(`Invalid query JSON: ${getErrorMessage(error)}`)
}
}
if (params.isStatic !== undefined) body.is_static = params.isStatic
if (params.groups) {
try {
body.groups = JSON.parse(params.groups)
} catch (error) {
throw new Error(`Invalid groups JSON: ${getErrorMessage(error)}`)
}
}
if (params.deleted !== undefined) body.deleted = params.deleted
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
groups: data.groups || [],
deleted: data.deleted || false,
filters: data.filters || {},
query: data.query || null,
created_at: data.created_at,
is_calculating: data.is_calculating || false,
count: data.count || 0,
is_static: data.is_static || false,
version: data.version || 0,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the cohort',
},
name: {
type: 'string',
description: 'Name of the cohort',
},
description: {
type: 'string',
description: 'Description of the cohort',
},
groups: {
type: 'array',
description: 'Groups that define the cohort',
},
deleted: {
type: 'boolean',
description: 'Whether the cohort is deleted',
},
filters: {
type: 'object',
description: 'Filter configuration for the cohort',
},
query: {
type: 'object',
description: 'Query configuration for the cohort',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when cohort was created',
},
is_calculating: {
type: 'boolean',
description: 'Whether the cohort is being calculated',
},
count: {
type: 'number',
description: 'Number of users in the cohort',
},
is_static: {
type: 'boolean',
description: 'Whether the cohort is static',
},
version: {
type: 'number',
description: 'Version number of the cohort',
},
},
}
@@ -0,0 +1,198 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogUpdateEventDefinitionParams {
projectId: string
eventDefinitionId: string
region: 'us' | 'eu'
host?: string
apiKey: string
description?: string
tags?: string
verified?: boolean
}
interface EventDefinition {
id: string
name: string
description: string
tags: string[]
created_at: string
last_seen_at: string | null
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
verified: boolean
verified_at: string | null
verified_by: string | null
}
export const updateEventDefinitionTool: ToolConfig<
PostHogUpdateEventDefinitionParams,
EventDefinition
> = {
id: 'posthog_update_event_definition',
name: 'PostHog Update Event Definition',
description:
'Update an event definition in PostHog. Can modify description, tags, and verification status to maintain clean event schemas.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
eventDefinitionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Event Definition ID to update',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated description for the event',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of tags to associate with the event',
},
verified: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to mark the event as verified',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/event_definitions/${params.eventDefinitionId}`
},
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.description !== undefined) {
body.description = params.description
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0)
}
if (params.verified !== undefined) {
body.verified = params.verified
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
id: data.id,
name: data.name,
description: data.description || '',
tags: data.tags || [],
created_at: data.created_at,
last_seen_at: data.last_seen_at ?? null,
updated_at: data.updated_at,
updated_by: data.updated_by ?? null,
verified: data.verified || false,
verified_at: data.verified_at ?? null,
verified_by: data.verified_by ?? null,
}
},
outputs: {
id: {
type: 'string',
description: 'Unique identifier for the event definition',
},
name: {
type: 'string',
description: 'Event name',
},
description: {
type: 'string',
description: 'Updated event description',
},
tags: {
type: 'array',
description: 'Updated tags associated with the event',
},
created_at: {
type: 'string',
description: 'ISO timestamp when the event was created',
},
last_seen_at: {
type: 'string',
description: 'ISO timestamp when the event was last seen',
optional: true,
},
updated_at: {
type: 'string',
description: 'ISO timestamp when the event was updated',
},
updated_by: {
type: 'object',
description: 'User who last updated the event',
optional: true,
},
verified: {
type: 'boolean',
description: 'Whether the event has been verified',
},
verified_at: {
type: 'string',
description: 'ISO timestamp when the event was verified',
optional: true,
},
verified_by: {
type: 'string',
description: 'User who verified the event',
optional: true,
},
},
}
+190
View File
@@ -0,0 +1,190 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface UpdateExperimentParams {
projectId: string
experimentId: string
region?: 'us' | 'eu'
host?: string
apiKey: string
name?: string
description?: string
parameters?: string
filters?: string
startDate?: string
endDate?: string
archived?: boolean
}
interface Experiment {
id: number
name: string
description: string
feature_flag_key: string
feature_flag: Record<string, any>
parameters: Record<string, any>
filters: Record<string, any>
start_date: string | null
end_date: string | null
created_at: string
archived: boolean
}
interface UpdateExperimentResponse {
experiment: Experiment
}
export const updateExperimentTool: ToolConfig<UpdateExperimentParams, UpdateExperimentResponse> = {
id: 'posthog_update_experiment',
name: 'PostHog Update Experiment',
description:
'Update an existing experiment in PostHog. Use this to change dates, archive an experiment, or adjust its parameters and filters.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
experimentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The experiment ID to update (e.g., "42")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated experiment name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated experiment description',
},
parameters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated experiment parameters as JSON string',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated experiment filters as JSON string',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated start date (ISO 8601). Set this to launch a draft experiment.',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated end date (ISO 8601). Set this to conclude a running experiment.',
},
archived: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to archive the experiment',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/experiments/${params.experimentId}/`
},
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name !== undefined) body.name = params.name
if (params.description !== undefined) body.description = params.description
if (params.parameters) {
try {
body.parameters = JSON.parse(params.parameters)
} catch (error) {
throw new Error(`Invalid parameters JSON: ${getErrorMessage(error)}`)
}
}
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (error) {
throw new Error(`Invalid filters JSON: ${getErrorMessage(error)}`)
}
}
if (params.startDate !== undefined) body.start_date = params.startDate
if (params.endDate !== undefined) body.end_date = params.endDate
if (params.archived !== undefined) body.archived = params.archived
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
experiment: data,
}
},
outputs: {
experiment: {
type: 'object',
description: 'Updated experiment',
properties: {
id: { type: 'number', description: 'Experiment ID' },
name: { type: 'string', description: 'Experiment name' },
description: { type: 'string', description: 'Experiment description' },
feature_flag_key: { type: 'string', description: 'Associated feature flag key' },
feature_flag: { type: 'object', description: 'Feature flag details' },
parameters: { type: 'object', description: 'Experiment parameters' },
filters: { type: 'object', description: 'Experiment filters' },
start_date: { type: 'string', description: 'Start date', optional: true },
end_date: { type: 'string', description: 'End date', optional: true },
created_at: { type: 'string', description: 'Creation timestamp' },
archived: { type: 'boolean', description: 'Whether the experiment is archived' },
},
},
},
}
@@ -0,0 +1,193 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface UpdateFeatureFlagParams {
projectId: string
flagId: string
region: 'us' | 'eu'
host?: string
apiKey: string
name?: string
key?: string
filters?: string
active?: boolean
ensureExperienceContinuity?: boolean
rolloutPercentage?: number
}
interface FeatureFlag {
id: number
name: string
key: string
filters: Record<string, any>
deleted: boolean
active: boolean
created_at: string
created_by: Record<string, any>
is_simple_flag: boolean
rollout_percentage: number | null
ensure_experience_continuity: boolean
}
interface UpdateFeatureFlagResponse {
flag: FeatureFlag
}
export const updateFeatureFlagTool: ToolConfig<UpdateFeatureFlagParams, UpdateFeatureFlagResponse> =
{
id: 'posthog_update_feature_flag',
name: 'PostHog Update Feature Flag',
description: 'Update an existing feature flag in PostHog',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
flagId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The feature flag ID (e.g., "42")',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag name',
},
key: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag key (unique identifier)',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag filters as JSON string',
},
active: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the flag is active',
},
ensureExperienceContinuity: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to ensure experience continuity',
},
rolloutPercentage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Rollout percentage (0-100)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/feature_flags/${params.flagId}/`
},
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name !== undefined) {
body.name = params.name
}
if (params.key !== undefined && params.key !== '') {
body.key = params.key
}
if (params.filters) {
try {
body.filters = JSON.parse(params.filters)
} catch (error) {
throw new Error(`Invalid filters JSON: ${getErrorMessage(error)}`)
}
}
if (params.active !== undefined) {
body.active = params.active
}
if (params.ensureExperienceContinuity !== undefined) {
body.ensure_experience_continuity = params.ensureExperienceContinuity
}
if (params.rolloutPercentage !== undefined) {
body.rollout_percentage = params.rolloutPercentage
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
flag: data,
}
},
outputs: {
flag: {
type: 'object',
description: 'Updated feature flag',
properties: {
id: { type: 'number', description: 'Feature flag ID' },
name: { type: 'string', description: 'Feature flag name' },
key: { type: 'string', description: 'Feature flag key' },
filters: { type: 'object', description: 'Feature flag filters' },
deleted: { type: 'boolean', description: 'Whether the flag is deleted' },
active: { type: 'boolean', description: 'Whether the flag is active' },
created_at: { type: 'string', description: 'Creation timestamp' },
created_by: { type: 'object', description: 'Creator information' },
is_simple_flag: { type: 'boolean', description: 'Whether this is a simple flag' },
rollout_percentage: {
type: 'number',
description: 'Rollout percentage (if applicable)',
},
ensure_experience_continuity: {
type: 'boolean',
description: 'Whether to ensure experience continuity',
},
},
},
},
}
+218
View File
@@ -0,0 +1,218 @@
import { getErrorMessage } from '@sim/utils/errors'
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogUpdateInsightParams {
apiKey: string
projectId: string
insightId: string
region?: 'us' | 'eu'
host?: string
name?: string
description?: string
query?: string
dashboards?: string
tags?: string
favorited?: boolean
}
interface PostHogUpdateInsightResponse {
success: boolean
output: {
id: number
name: string
description: string
query: Record<string, any> | null
created_at: string
last_modified_at: string
dashboards: number[]
tags: string[]
favorited: boolean
}
}
export const updateInsightTool: ToolConfig<
PostHogUpdateInsightParams,
PostHogUpdateInsightResponse
> = {
id: 'posthog_update_insight',
name: 'PostHog Update Insight',
description:
'Update an existing insight in PostHog. Can modify name, description, query, dashboards, tags, and favorited status.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The PostHog project ID (e.g., "12345" or project UUID)',
},
insightId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The insight ID to update (e.g., "42" or short ID like "abc123")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description: 'Updated name for the insight',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated description for the insight',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of updated query configuration for the insight',
},
dashboards: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of dashboard IDs to attach this insight to',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of tags for the insight',
},
favorited: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to mark the insight as favorited',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/insights/${params.insightId}/`
},
method: 'PATCH',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name !== undefined) body.name = params.name
if (params.description !== undefined) body.description = params.description
if (params.query) {
try {
body.query = JSON.parse(params.query)
} catch (error) {
throw new Error(`Invalid query JSON: ${getErrorMessage(error)}`)
}
}
if (params.dashboards) {
body.dashboards = params.dashboards
.split(',')
.map((id: string) => Number(id.trim()))
.filter((id: number) => !Number.isNaN(id))
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0)
}
if (params.favorited !== undefined) body.favorited = params.favorited
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name || '',
description: data.description || '',
query: data.query || null,
created_at: data.created_at,
last_modified_at: data.last_modified_at,
dashboards: data.dashboards || [],
tags: data.tags || [],
favorited: data.favorited || false,
},
}
},
outputs: {
id: {
type: 'number',
description: 'Unique identifier for the insight',
},
name: {
type: 'string',
description: 'Name of the insight',
},
description: {
type: 'string',
description: 'Description of the insight',
},
query: {
type: 'object',
description: 'Query configuration for the insight',
optional: true,
},
created_at: {
type: 'string',
description: 'ISO timestamp when insight was created',
},
last_modified_at: {
type: 'string',
description: 'ISO timestamp when insight was last modified',
},
dashboards: {
type: 'array',
description: 'IDs of dashboards this insight appears on',
},
tags: {
type: 'array',
description: 'Tags associated with the insight',
},
favorited: {
type: 'boolean',
description: 'Whether the insight is favorited',
},
},
}
@@ -0,0 +1,227 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogUpdatePropertyDefinitionParams {
projectId: string
propertyDefinitionId: string
region: 'us' | 'eu'
host?: string
apiKey: string
description?: string
tags?: string
verified?: boolean
property_type?: string
}
interface PropertyDefinition {
id: string
name: string
description: string
tags: string[]
is_numerical: boolean
is_seen_on_filtered_events: boolean | null
property_type: string
type: 'event' | 'person' | 'group' | 'session'
created_at: string
updated_at: string
updated_by: {
id: number
uuid: string
distinct_id: string
first_name: string
email: string
} | null
verified: boolean
verified_at: string | null
verified_by: string | null
}
export const updatePropertyDefinitionTool: ToolConfig<
PostHogUpdatePropertyDefinitionParams,
PropertyDefinition
> = {
id: 'posthog_update_property_definition',
name: 'PostHog Update Property Definition',
description:
'Update a property definition in PostHog. Can modify description, tags, property type, and verification status to maintain clean property schemas.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
propertyDefinitionId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Property Definition ID to update',
},
region: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog cloud region: us or eu',
},
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.',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated description for the property',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of tags to associate with the property',
},
verified: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to mark the property as verified',
},
property_type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The data type of the property (e.g., String, Numeric, Boolean, DateTime, etc.)',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/property_definitions/${params.propertyDefinitionId}`
},
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.description !== undefined) {
body.description = params.description
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((tag: string) => tag.trim())
.filter((tag: string) => tag.length > 0)
}
if (params.verified !== undefined) {
body.verified = params.verified
}
if (params.property_type !== undefined) {
body.property_type = params.property_type
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
id: data.id,
name: data.name,
description: data.description || '',
tags: data.tags || [],
is_numerical: data.is_numerical || false,
is_seen_on_filtered_events: data.is_seen_on_filtered_events ?? null,
property_type: data.property_type,
type: data.type,
created_at: data.created_at,
updated_at: data.updated_at,
updated_by: data.updated_by ?? null,
verified: data.verified || false,
verified_at: data.verified_at ?? null,
verified_by: data.verified_by ?? null,
}
},
outputs: {
id: {
type: 'string',
description: 'Unique identifier for the property definition',
},
name: {
type: 'string',
description: 'Property name',
},
description: {
type: 'string',
description: 'Updated property description',
},
tags: {
type: 'array',
description: 'Updated tags associated with the property',
},
is_numerical: {
type: 'boolean',
description: 'Whether the property is numerical',
},
is_seen_on_filtered_events: {
type: 'boolean',
description: 'Whether the property is seen on filtered events',
optional: true,
},
property_type: {
type: 'string',
description: 'The data type of the property',
},
type: {
type: 'string',
description: 'Property type: event, person, group, or session',
},
created_at: {
type: 'string',
description: 'ISO timestamp when the property was created',
},
updated_at: {
type: 'string',
description: 'ISO timestamp when the property was updated',
},
updated_by: {
type: 'object',
description: 'User who last updated the property',
optional: true,
},
verified: {
type: 'boolean',
description: 'Whether the property has been verified',
},
verified_at: {
type: 'string',
description: 'ISO timestamp when the property was verified',
optional: true,
},
verified_by: {
type: 'string',
description: 'User who verified the property',
optional: true,
},
},
}
+242
View File
@@ -0,0 +1,242 @@
import { getPostHogAppBaseUrl } from '@/tools/posthog/utils'
import type { ToolConfig } from '@/tools/types'
interface PostHogSurveyQuestion {
type: 'open' | 'link' | 'rating' | 'multiple_choice'
question: string
description?: string
choices?: string[]
scale?: number
lowerBoundLabel?: string
upperBoundLabel?: string
buttonText?: string
}
interface PostHogUpdateSurveyParams {
apiKey: string
projectId: string
surveyId: string
region?: 'us' | 'eu'
host?: string
name?: string
description?: string
type?: 'popover' | 'api'
questions?: string // JSON string of questions array
startDate?: string
endDate?: string
appearance?: string // JSON string of appearance config
conditions?: string // JSON string of conditions
targetingFlagFilters?: string // JSON string of targeting filters
linkedFlagId?: string
responsesLimit?: number
archived?: boolean
}
interface PostHogSurvey {
id: string
name: string
description: string
type: 'popover' | 'api'
questions: PostHogSurveyQuestion[]
appearance?: Record<string, any>
conditions?: Record<string, any>
created_at: string
created_by: Record<string, any>
start_date?: string
end_date?: string
archived?: boolean
targeting_flag_filters?: Record<string, any>
linked_flag?: Record<string, any>
responses_limit?: number
}
interface PostHogUpdateSurveyResponse {
success: boolean
output: {
survey: PostHogSurvey
}
}
export const updateSurveyTool: ToolConfig<PostHogUpdateSurveyParams, PostHogUpdateSurveyResponse> =
{
id: 'posthog_update_survey',
name: 'PostHog Update Survey',
description:
'Update an existing survey in PostHog. Can modify questions, appearance, conditions, and other settings.',
version: '1.0.0',
errorExtractor: 'posthog-errors',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'PostHog Personal API Key',
},
projectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'PostHog Project ID (e.g., "12345" or project UUID)',
},
surveyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Survey ID to update (e.g., "01234567-89ab-cdef-0123-456789abcdef")',
},
region: {
type: 'string',
required: false,
visibility: 'user-only',
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,
visibility: 'user-or-llm',
description: 'Survey name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey description',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey type: popover or api',
},
questions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'JSON string of survey questions array. Each question must have type (open/link/rating/multiple_choice) and question text.',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey start date in ISO 8601 format',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Survey end date in ISO 8601 format',
},
appearance: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of appearance configuration (colors, position, etc.)',
},
conditions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of display conditions (URL matching, etc.)',
},
targetingFlagFilters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON string of feature flag filters for targeting',
},
linkedFlagId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Feature flag ID to link to this survey',
},
responsesLimit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of responses to collect',
},
archived: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Archive or unarchive the survey',
},
},
request: {
url: (params) => {
const baseUrl = getPostHogAppBaseUrl(params.region, params.host)
return `${baseUrl}/api/projects/${params.projectId}/surveys/${params.surveyId}/`
},
method: 'PATCH',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name !== undefined) body.name = params.name
if (params.description !== undefined) body.description = params.description
if (params.type !== undefined) body.type = params.type
if (params.questions) body.questions = JSON.parse(params.questions)
if (params.startDate !== undefined) body.start_date = params.startDate
if (params.endDate !== undefined) body.end_date = params.endDate
if (params.appearance) body.appearance = JSON.parse(params.appearance)
if (params.conditions) body.conditions = JSON.parse(params.conditions)
if (params.targetingFlagFilters) {
body.targeting_flag_filters = JSON.parse(params.targetingFlagFilters)
}
if (params.linkedFlagId !== undefined && params.linkedFlagId !== '') {
body.linked_flag_id = params.linkedFlagId
}
if (params.responsesLimit !== undefined) body.responses_limit = params.responsesLimit
if (params.archived !== undefined) body.archived = params.archived
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
survey: data,
},
}
},
outputs: {
survey: {
type: 'object',
description: 'Updated survey details',
properties: {
id: { type: 'string', description: 'Survey ID' },
name: { type: 'string', description: 'Survey name' },
description: { type: 'string', description: 'Survey description' },
type: { type: 'string', description: 'Survey type (popover or api)' },
questions: {
type: 'array',
description: 'Survey questions',
},
created_at: { type: 'string', description: 'Creation timestamp' },
start_date: { type: 'string', description: 'Survey start date' },
end_date: { type: 'string', description: 'Survey end date' },
archived: { type: 'boolean', description: 'Whether survey is archived' },
},
},
},
}
+40
View File
@@ -0,0 +1,40 @@
import { validateExternalUrl } from '@/lib/core/security/input-validation'
/**
* Shared PostHog base URL resolution.
*
* PostHog exposes two host families:
* - The "app" REST API (`/api/...`) at `us.posthog.com` / `eu.posthog.com`, authenticated
* with a personal API key.
* - The "ingest" API (`/i/v0/e`, `/batch/`, `/flags/`) at `us.i.posthog.com` / `eu.i.posthog.com`,
* authenticated with a project API key.
*
* Self-hosted PostHog instances serve both families from a single custom host. That host is
* validated with the shared SSRF guard so it can't be pointed at loopback/private/link-local
* addresses (e.g. cloud instance-metadata endpoints); the tool executor additionally
* re-validates with DNS resolution and pins the resolved IP for the actual request.
*/
export function getPostHogAppBaseUrl(region?: 'us' | 'eu', host?: string): string {
if (host?.trim()) {
return normalizeHost(host)
}
return region === 'eu' ? 'https://eu.posthog.com' : 'https://us.posthog.com'
}
export function getPostHogIngestBaseUrl(region?: 'us' | 'eu', host?: string): string {
if (host?.trim()) {
return normalizeHost(host)
}
return region === 'eu' ? 'https://eu.i.posthog.com' : 'https://us.i.posthog.com'
}
function normalizeHost(host: string): string {
const trimmed = host.trim().replace(/\/+$/, '')
const withProtocol = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`
const validation = validateExternalUrl(withProtocol, 'Self-hosted host')
if (!validation.isValid) {
throw new Error(`${validation.error} (e.g., posthog.mycompany.com)`)
}
return withProtocol
}