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
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:
@@ -0,0 +1,137 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundBotLogsParams, ProfoundBotLogsResponse } from './types'
|
||||
|
||||
export const profoundBotLogsTool: ToolConfig<ProfoundBotLogsParams, ProfoundBotLogsResponse> = {
|
||||
id: 'profound_bot_logs',
|
||||
name: 'Profound Bot Logs',
|
||||
description: 'Get identified bot visit logs with filters for a domain in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to query bot logs for (e.g. example.com)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601). Defaults to now',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: timestamp, method, host, path, status_code, ip, user_agent, referer, bytes_sent, duration_ms, query_params, bot_name, bot_provider, bot_types',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"bot_name","operator":"is","value":"GPTBot"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/logs/raw/bots',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
domain: params.domain,
|
||||
start_date: params.startDate,
|
||||
metrics: ['count'],
|
||||
}
|
||||
if (params.endDate) {
|
||||
body.end_date = params.endDate
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to get bot logs')
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.length,
|
||||
data: data.map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of bot log entries',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Bot log data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: { type: 'json', description: 'Array of metric values (count)' },
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundBotsReportParams, ProfoundBotsReportResponse } from './types'
|
||||
|
||||
export const profoundBotsReportTool: ToolConfig<
|
||||
ProfoundBotsReportParams,
|
||||
ProfoundBotsReportResponse
|
||||
> = {
|
||||
id: 'profound_bots_report',
|
||||
name: 'Profound Bots Report',
|
||||
description: 'Query bot traffic report with hourly granularity for a domain in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to query bot traffic for (e.g. example.com)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601). Defaults to now',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: count, citations, indexing, training, last_visit',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated dimensions: date, hour, path, bot_name, bot_provider, bot_type',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"bot_name","operator":"is","value":"GPTBot"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v2/reports/bots',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
domain: params.domain,
|
||||
start_date: params.startDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.endDate) {
|
||||
body.end_date = params.endDate
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query bots report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCategoryAssetsParams, ProfoundCategoryAssetsResponse } from './types'
|
||||
|
||||
export const profoundCategoryAssetsTool: ToolConfig<
|
||||
ProfoundCategoryAssetsParams,
|
||||
ProfoundCategoryAssetsResponse
|
||||
> = {
|
||||
id: 'profound_category_assets',
|
||||
name: 'Profound Category Assets',
|
||||
description: 'List assets (companies/brands) for a specific category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.tryprofound.com/v1/org/categories/${encodeURIComponent(params.categoryId)}/assets`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list category assets')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
assets: (data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
name: string
|
||||
website: string
|
||||
alternate_domains: string[] | null
|
||||
is_owned: boolean
|
||||
created_at: string
|
||||
logo_url: string
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
website: item.website ?? null,
|
||||
alternateDomains: item.alternate_domains ?? null,
|
||||
isOwned: item.is_owned ?? false,
|
||||
createdAt: item.created_at ?? null,
|
||||
logoUrl: item.logo_url ?? null,
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
assets: {
|
||||
type: 'json',
|
||||
description: 'List of assets in the category',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Asset ID' },
|
||||
name: { type: 'string', description: 'Asset/company name' },
|
||||
website: { type: 'string', description: 'Website URL' },
|
||||
alternateDomains: { type: 'json', description: 'Alternate domain names' },
|
||||
isOwned: { type: 'boolean', description: 'Whether the asset is owned by the organization' },
|
||||
createdAt: { type: 'string', description: 'When the asset was created' },
|
||||
logoUrl: { type: 'string', description: 'URL of the asset logo' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCategoryPersonasParams, ProfoundCategoryPersonasResponse } from './types'
|
||||
|
||||
export const profoundCategoryPersonasTool: ToolConfig<
|
||||
ProfoundCategoryPersonasParams,
|
||||
ProfoundCategoryPersonasResponse
|
||||
> = {
|
||||
id: 'profound_category_personas',
|
||||
name: 'Profound Category Personas',
|
||||
description: 'List personas for a specific category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.tryprofound.com/v1/org/categories/${encodeURIComponent(params.categoryId)}/personas`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list category personas')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
personas: (data.data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
name: string
|
||||
persona: {
|
||||
behavior: { painPoints: string | null; motivations: string | null }
|
||||
employment: {
|
||||
industry: string[]
|
||||
jobTitle: string[]
|
||||
companySize: string[]
|
||||
roleSeniority: string[]
|
||||
}
|
||||
demographics: { ageRange: string[] }
|
||||
}
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
persona: {
|
||||
behavior: {
|
||||
painPoints: item.persona?.behavior?.painPoints ?? null,
|
||||
motivations: item.persona?.behavior?.motivations ?? null,
|
||||
},
|
||||
employment: {
|
||||
industry: item.persona?.employment?.industry ?? [],
|
||||
jobTitle: item.persona?.employment?.jobTitle ?? [],
|
||||
companySize: item.persona?.employment?.companySize ?? [],
|
||||
roleSeniority: item.persona?.employment?.roleSeniority ?? [],
|
||||
},
|
||||
demographics: {
|
||||
ageRange: item.persona?.demographics?.ageRange ?? [],
|
||||
},
|
||||
},
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
personas: {
|
||||
type: 'json',
|
||||
description: 'List of personas in the category',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Persona ID' },
|
||||
name: { type: 'string', description: 'Persona name' },
|
||||
persona: {
|
||||
type: 'json',
|
||||
description: 'Persona profile with behavior, employment, and demographics',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCategoryPromptsParams, ProfoundCategoryPromptsResponse } from './types'
|
||||
|
||||
export const profoundCategoryPromptsTool: ToolConfig<
|
||||
ProfoundCategoryPromptsParams,
|
||||
ProfoundCategoryPromptsResponse
|
||||
> = {
|
||||
id: 'profound_category_prompts',
|
||||
name: 'Profound Category Prompts',
|
||||
description: 'List prompts for a specific category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 10000)',
|
||||
},
|
||||
cursor: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pagination cursor from previous response',
|
||||
},
|
||||
orderDir: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction: asc or desc (default desc)',
|
||||
},
|
||||
promptType: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated prompt types to filter: visibility, sentiment',
|
||||
},
|
||||
topicId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated topic IDs (UUIDs) to filter by',
|
||||
},
|
||||
tagId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated tag IDs (UUIDs) to filter by',
|
||||
},
|
||||
regionId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated region IDs (UUIDs) to filter by',
|
||||
},
|
||||
platformId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated platform IDs (UUIDs) to filter by',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://api.tryprofound.com/v1/org/categories/${encodeURIComponent(params.categoryId)}/prompts`
|
||||
)
|
||||
if (params.limit != null) url.searchParams.set('limit', String(params.limit))
|
||||
if (params.cursor) url.searchParams.set('cursor', params.cursor)
|
||||
if (params.orderDir) url.searchParams.set('order_dir', params.orderDir)
|
||||
if (params.promptType) {
|
||||
for (const pt of params.promptType.split(',').map((s) => s.trim())) {
|
||||
url.searchParams.append('prompt_type', pt)
|
||||
}
|
||||
}
|
||||
if (params.topicId) {
|
||||
for (const tid of params.topicId.split(',').map((s) => s.trim())) {
|
||||
url.searchParams.append('topic_id', tid)
|
||||
}
|
||||
}
|
||||
if (params.tagId) {
|
||||
for (const tid of params.tagId.split(',').map((s) => s.trim())) {
|
||||
url.searchParams.append('tag_id', tid)
|
||||
}
|
||||
}
|
||||
if (params.regionId) {
|
||||
for (const rid of params.regionId.split(',').map((s) => s.trim())) {
|
||||
url.searchParams.append('region_id', rid)
|
||||
}
|
||||
}
|
||||
if (params.platformId) {
|
||||
for (const pid of params.platformId.split(',').map((s) => s.trim())) {
|
||||
url.searchParams.append('platform_id', pid)
|
||||
}
|
||||
}
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list category prompts')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
nextCursor: data.info?.next_cursor ?? null,
|
||||
prompts: (data.data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
prompt: string
|
||||
prompt_type: string
|
||||
topic: { id: string; name: string }
|
||||
tags: Array<{ id: string; name: string }>
|
||||
regions: Array<{ id: string; name: string }>
|
||||
platforms: Array<{ id: string; name: string }>
|
||||
created_at: string
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
prompt: item.prompt ?? null,
|
||||
promptType: item.prompt_type ?? null,
|
||||
topicId: item.topic?.id ?? null,
|
||||
topicName: item.topic?.name ?? null,
|
||||
tags: (item.tags ?? []).map((t: { id: string; name: string }) => ({
|
||||
id: t.id ?? null,
|
||||
name: t.name ?? null,
|
||||
})),
|
||||
regions: (item.regions ?? []).map((r: { id: string; name: string }) => ({
|
||||
id: r.id ?? null,
|
||||
name: r.name ?? null,
|
||||
})),
|
||||
platforms: (item.platforms ?? []).map((p: { id: string; name: string }) => ({
|
||||
id: p.id ?? null,
|
||||
name: p.name ?? null,
|
||||
})),
|
||||
createdAt: item.created_at ?? null,
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of prompts',
|
||||
},
|
||||
nextCursor: {
|
||||
type: 'string',
|
||||
description: 'Cursor for next page of results',
|
||||
optional: true,
|
||||
},
|
||||
prompts: {
|
||||
type: 'json',
|
||||
description: 'List of prompts',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Prompt ID' },
|
||||
prompt: { type: 'string', description: 'Prompt text' },
|
||||
promptType: { type: 'string', description: 'Prompt type (visibility or sentiment)' },
|
||||
topicId: { type: 'string', description: 'Topic ID' },
|
||||
topicName: { type: 'string', description: 'Topic name' },
|
||||
tags: { type: 'json', description: 'Associated tags' },
|
||||
regions: { type: 'json', description: 'Associated regions' },
|
||||
platforms: { type: 'json', description: 'Associated platforms' },
|
||||
createdAt: { type: 'string', description: 'When the prompt was created' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCategoryTagsParams, ProfoundCategoryTagsResponse } from './types'
|
||||
|
||||
export const profoundCategoryTagsTool: ToolConfig<
|
||||
ProfoundCategoryTagsParams,
|
||||
ProfoundCategoryTagsResponse
|
||||
> = {
|
||||
id: 'profound_category_tags',
|
||||
name: 'Profound Category Tags',
|
||||
description: 'List tags for a specific category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.tryprofound.com/v1/org/categories/${encodeURIComponent(params.categoryId)}/tags`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list category tags')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
tags: (data ?? []).map((item: { id: string; name: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
tags: {
|
||||
type: 'json',
|
||||
description: 'List of tags in the category',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Tag ID (UUID)' },
|
||||
name: { type: 'string', description: 'Tag name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCategoryTopicsParams, ProfoundCategoryTopicsResponse } from './types'
|
||||
|
||||
export const profoundCategoryTopicsTool: ToolConfig<
|
||||
ProfoundCategoryTopicsParams,
|
||||
ProfoundCategoryTopicsResponse
|
||||
> = {
|
||||
id: 'profound_category_topics',
|
||||
name: 'Profound Category Topics',
|
||||
description: 'List topics for a specific category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.tryprofound.com/v1/org/categories/${encodeURIComponent(params.categoryId)}/topics`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list category topics')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
topics: (data ?? []).map((item: { id: string; name: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
topics: {
|
||||
type: 'json',
|
||||
description: 'List of topics in the category',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Topic ID (UUID)' },
|
||||
name: { type: 'string', description: 'Topic name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCitationPromptsParams, ProfoundCitationPromptsResponse } from './types'
|
||||
|
||||
export const profoundCitationPromptsTool: ToolConfig<
|
||||
ProfoundCitationPromptsParams,
|
||||
ProfoundCitationPromptsResponse
|
||||
> = {
|
||||
id: 'profound_citation_prompts',
|
||||
name: 'Profound Citation Prompts',
|
||||
description: 'Get prompts that cite a specific domain across AI platforms in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
inputDomain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to look up citations for (e.g. ramp.com)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.tryprofound.com/v1/prompt-volumes/citation-prompts')
|
||||
url.searchParams.set('input_domain', params.inputDomain)
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to get citation prompts')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
data: data ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Citation prompt data for the queried domain',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundCitationsReportParams, ProfoundCitationsReportResponse } from './types'
|
||||
|
||||
export const profoundCitationsReportTool: ToolConfig<
|
||||
ProfoundCitationsReportParams,
|
||||
ProfoundCitationsReportResponse
|
||||
> = {
|
||||
id: 'profound_citations_report',
|
||||
name: 'Profound Citations Report',
|
||||
description: 'Query citations report for a category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: count, citation_share',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: hostname, path, date, region, topic, model, tag, prompt, url, root_domain, persona, citation_category',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"hostname","operator":"is","value":"example.com"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/reports/citations',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
category_id: params.categoryId,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query citations report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
export { profoundBotLogsTool } from './bot_logs'
|
||||
export { profoundBotsReportTool } from './bots_report'
|
||||
export { profoundCategoryAssetsTool } from './category_assets'
|
||||
export { profoundCategoryPersonasTool } from './category_personas'
|
||||
export { profoundCategoryPromptsTool } from './category_prompts'
|
||||
export { profoundCategoryTagsTool } from './category_tags'
|
||||
export { profoundCategoryTopicsTool } from './category_topics'
|
||||
export { profoundCitationPromptsTool } from './citation_prompts'
|
||||
export { profoundCitationsReportTool } from './citations_report'
|
||||
export { profoundListAssetsTool } from './list_assets'
|
||||
export { profoundListCategoriesTool } from './list_categories'
|
||||
export { profoundListDomainsTool } from './list_domains'
|
||||
export { profoundListModelsTool } from './list_models'
|
||||
export { profoundListOptimizationsTool } from './list_optimizations'
|
||||
export { profoundListPersonasTool } from './list_personas'
|
||||
export { profoundListRegionsTool } from './list_regions'
|
||||
export { profoundOptimizationAnalysisTool } from './optimization_analysis'
|
||||
export { profoundPromptAnswersTool } from './prompt_answers'
|
||||
export { profoundPromptVolumeTool } from './prompt_volume'
|
||||
export { profoundQueryFanoutsTool } from './query_fanouts'
|
||||
export { profoundRawLogsTool } from './raw_logs'
|
||||
export { profoundReferralsReportTool } from './referrals_report'
|
||||
export { profoundSentimentReportTool } from './sentiment_report'
|
||||
export { profoundVisibilityReportTool } from './visibility_report'
|
||||
@@ -0,0 +1,85 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListAssetsParams, ProfoundListAssetsResponse } from './types'
|
||||
|
||||
export const profoundListAssetsTool: ToolConfig<
|
||||
ProfoundListAssetsParams,
|
||||
ProfoundListAssetsResponse
|
||||
> = {
|
||||
id: 'profound_list_assets',
|
||||
name: 'Profound List Assets',
|
||||
description: 'List all organization assets (companies/brands) across all categories in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/assets',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list assets')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
assets: (data.data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
name: string
|
||||
website: string
|
||||
alternate_domains: string[] | null
|
||||
is_owned: boolean
|
||||
created_at: string
|
||||
logo_url: string
|
||||
category: { id: string; name: string }
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
website: item.website ?? null,
|
||||
alternateDomains: item.alternate_domains ?? null,
|
||||
isOwned: item.is_owned ?? false,
|
||||
createdAt: item.created_at ?? null,
|
||||
logoUrl: item.logo_url ?? null,
|
||||
categoryId: item.category?.id ?? null,
|
||||
categoryName: item.category?.name ?? null,
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
assets: {
|
||||
type: 'json',
|
||||
description: 'List of organization assets with category info',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Asset ID' },
|
||||
name: { type: 'string', description: 'Asset/company name' },
|
||||
website: { type: 'string', description: 'Asset website URL' },
|
||||
alternateDomains: { type: 'json', description: 'Alternate domain names' },
|
||||
isOwned: {
|
||||
type: 'boolean',
|
||||
description: 'Whether this asset is owned by the organization',
|
||||
},
|
||||
createdAt: { type: 'string', description: 'When the asset was created' },
|
||||
logoUrl: { type: 'string', description: 'URL of the asset logo' },
|
||||
categoryId: { type: 'string', description: 'Category ID the asset belongs to' },
|
||||
categoryName: { type: 'string', description: 'Category name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListCategoriesParams, ProfoundListCategoriesResponse } from './types'
|
||||
|
||||
export const profoundListCategoriesTool: ToolConfig<
|
||||
ProfoundListCategoriesParams,
|
||||
ProfoundListCategoriesResponse
|
||||
> = {
|
||||
id: 'profound_list_categories',
|
||||
name: 'Profound List Categories',
|
||||
description: 'List all organization categories in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/categories',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list categories')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
categories: (data ?? []).map((item: { id: string; name: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
categories: {
|
||||
type: 'json',
|
||||
description: 'List of organization categories',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Category ID' },
|
||||
name: { type: 'string', description: 'Category name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListDomainsParams, ProfoundListDomainsResponse } from './types'
|
||||
|
||||
export const profoundListDomainsTool: ToolConfig<
|
||||
ProfoundListDomainsParams,
|
||||
ProfoundListDomainsResponse
|
||||
> = {
|
||||
id: 'profound_list_domains',
|
||||
name: 'Profound List Domains',
|
||||
description: 'List all organization domains in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/domains',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list domains')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
domains: (data ?? []).map((item: { id: string; name: string; created_at: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
createdAt: item.created_at ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
domains: {
|
||||
type: 'json',
|
||||
description: 'List of organization domains',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Domain ID (UUID)' },
|
||||
name: { type: 'string', description: 'Domain name' },
|
||||
createdAt: { type: 'string', description: 'When the domain was added' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListModelsParams, ProfoundListModelsResponse } from './types'
|
||||
|
||||
export const profoundListModelsTool: ToolConfig<
|
||||
ProfoundListModelsParams,
|
||||
ProfoundListModelsResponse
|
||||
> = {
|
||||
id: 'profound_list_models',
|
||||
name: 'Profound List Models',
|
||||
description: 'List all AI models/platforms tracked in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/models',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list models')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
models: (data ?? []).map((item: { id: string; name: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
models: {
|
||||
type: 'json',
|
||||
description: 'List of AI models/platforms',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Model ID (UUID)' },
|
||||
name: { type: 'string', description: 'Model/platform name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListOptimizationsParams, ProfoundListOptimizationsResponse } from './types'
|
||||
|
||||
export const profoundListOptimizationsTool: ToolConfig<
|
||||
ProfoundListOptimizationsParams,
|
||||
ProfoundListOptimizationsResponse
|
||||
> = {
|
||||
id: 'profound_list_optimizations',
|
||||
name: 'Profound List Optimizations',
|
||||
description: 'List content optimization entries for an asset in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
assetId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Asset ID (UUID)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
offset: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Offset for pagination (default 0)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://api.tryprofound.com/v1/content/${encodeURIComponent(params.assetId)}/optimization`
|
||||
)
|
||||
if (params.limit != null) url.searchParams.set('limit', String(params.limit))
|
||||
if (params.offset != null) url.searchParams.set('offset', String(params.offset))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list optimizations')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
optimizations: (data.data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
title: string
|
||||
created_at: string
|
||||
extracted_input: string | null
|
||||
type: string
|
||||
status: string
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
title: item.title ?? null,
|
||||
createdAt: item.created_at ?? null,
|
||||
extractedInput: item.extracted_input ?? null,
|
||||
type: item.type ?? null,
|
||||
status: item.status ?? null,
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of optimization entries',
|
||||
},
|
||||
optimizations: {
|
||||
type: 'json',
|
||||
description: 'List of content optimization entries',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Optimization ID (UUID)' },
|
||||
title: { type: 'string', description: 'Content title' },
|
||||
createdAt: { type: 'string', description: 'When the optimization was created' },
|
||||
extractedInput: { type: 'string', description: 'Extracted input text' },
|
||||
type: { type: 'string', description: 'Content type: file, text, or url' },
|
||||
status: { type: 'string', description: 'Optimization status' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListPersonasParams, ProfoundListPersonasResponse } from './types'
|
||||
|
||||
export const profoundListPersonasTool: ToolConfig<
|
||||
ProfoundListPersonasParams,
|
||||
ProfoundListPersonasResponse
|
||||
> = {
|
||||
id: 'profound_list_personas',
|
||||
name: 'Profound List Personas',
|
||||
description: 'List all organization personas across all categories in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/personas',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list personas')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
personas: (data.data ?? []).map(
|
||||
(item: {
|
||||
id: string
|
||||
name: string
|
||||
category: { id: string; name: string }
|
||||
persona: {
|
||||
behavior: { painPoints: string | null; motivations: string | null }
|
||||
employment: {
|
||||
industry: string[]
|
||||
jobTitle: string[]
|
||||
companySize: string[]
|
||||
roleSeniority: string[]
|
||||
}
|
||||
demographics: { ageRange: string[] }
|
||||
}
|
||||
}) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
categoryId: item.category?.id ?? null,
|
||||
categoryName: item.category?.name ?? null,
|
||||
persona: {
|
||||
behavior: {
|
||||
painPoints: item.persona?.behavior?.painPoints ?? null,
|
||||
motivations: item.persona?.behavior?.motivations ?? null,
|
||||
},
|
||||
employment: {
|
||||
industry: item.persona?.employment?.industry ?? [],
|
||||
jobTitle: item.persona?.employment?.jobTitle ?? [],
|
||||
companySize: item.persona?.employment?.companySize ?? [],
|
||||
roleSeniority: item.persona?.employment?.roleSeniority ?? [],
|
||||
},
|
||||
demographics: {
|
||||
ageRange: item.persona?.demographics?.ageRange ?? [],
|
||||
},
|
||||
},
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
personas: {
|
||||
type: 'json',
|
||||
description: 'List of organization personas with profile details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Persona ID' },
|
||||
name: { type: 'string', description: 'Persona name' },
|
||||
categoryId: { type: 'string', description: 'Category ID' },
|
||||
categoryName: { type: 'string', description: 'Category name' },
|
||||
persona: {
|
||||
type: 'json',
|
||||
description: 'Persona profile with behavior, employment, and demographics',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundListRegionsParams, ProfoundListRegionsResponse } from './types'
|
||||
|
||||
export const profoundListRegionsTool: ToolConfig<
|
||||
ProfoundListRegionsParams,
|
||||
ProfoundListRegionsResponse
|
||||
> = {
|
||||
id: 'profound_list_regions',
|
||||
name: 'Profound List Regions',
|
||||
description: 'List all organization regions in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/org/regions',
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to list regions')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
regions: (data ?? []).map((item: { id: string; name: string }) => ({
|
||||
id: item.id ?? null,
|
||||
name: item.name ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
regions: {
|
||||
type: 'json',
|
||||
description: 'List of organization regions',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Region ID (UUID)' },
|
||||
name: { type: 'string', description: 'Region name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type {
|
||||
ProfoundOptimizationAnalysisParams,
|
||||
ProfoundOptimizationAnalysisResponse,
|
||||
} from './types'
|
||||
|
||||
export const profoundOptimizationAnalysisTool: ToolConfig<
|
||||
ProfoundOptimizationAnalysisParams,
|
||||
ProfoundOptimizationAnalysisResponse
|
||||
> = {
|
||||
id: 'profound_optimization_analysis',
|
||||
name: 'Profound Optimization Analysis',
|
||||
description: 'Get detailed content optimization analysis for a specific content item in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
assetId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Asset ID (UUID)',
|
||||
},
|
||||
contentId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Content/optimization ID (UUID)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.tryprofound.com/v1/content/${encodeURIComponent(params.assetId)}/optimization/${encodeURIComponent(params.contentId)}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to get optimization analysis')
|
||||
}
|
||||
const analysis = data.data
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: {
|
||||
format: analysis?.content?.format ?? null,
|
||||
value: analysis?.content?.value ?? null,
|
||||
},
|
||||
aeoContentScore: analysis?.aeo_content_score
|
||||
? {
|
||||
value: analysis.aeo_content_score.value ?? 0,
|
||||
targetZone: {
|
||||
low: analysis.aeo_content_score.target_zone?.low ?? 0,
|
||||
high: analysis.aeo_content_score.target_zone?.high ?? 0,
|
||||
},
|
||||
}
|
||||
: null,
|
||||
analysis: {
|
||||
breakdown: (analysis?.analysis?.breakdown ?? []).map(
|
||||
(b: { title: string; weight: number; score: number }) => ({
|
||||
title: b.title ?? null,
|
||||
weight: b.weight ?? 0,
|
||||
score: b.score ?? 0,
|
||||
})
|
||||
),
|
||||
},
|
||||
recommendations: (analysis?.recommendations ?? []).map(
|
||||
(r: {
|
||||
title: string
|
||||
status: string
|
||||
impact: { section: string; score: number } | null
|
||||
suggestion: { text: string; rationale: string }
|
||||
}) => ({
|
||||
title: r.title ?? null,
|
||||
status: r.status ?? null,
|
||||
impact: r.impact
|
||||
? {
|
||||
section: r.impact.section ?? null,
|
||||
score: r.impact.score ?? 0,
|
||||
}
|
||||
: null,
|
||||
suggestion: {
|
||||
text: r.suggestion?.text ?? null,
|
||||
rationale: r.suggestion?.rationale ?? null,
|
||||
},
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: {
|
||||
type: 'json',
|
||||
description: 'The analyzed content',
|
||||
properties: {
|
||||
format: { type: 'string', description: 'Content format: markdown or html' },
|
||||
value: { type: 'string', description: 'Content text' },
|
||||
},
|
||||
},
|
||||
aeoContentScore: {
|
||||
type: 'json',
|
||||
description: 'AEO content score with target zone',
|
||||
optional: true,
|
||||
properties: {
|
||||
value: { type: 'number', description: 'AEO score value' },
|
||||
targetZone: {
|
||||
type: 'json',
|
||||
description: 'Target zone range',
|
||||
properties: {
|
||||
low: { type: 'number', description: 'Low end of target range' },
|
||||
high: { type: 'number', description: 'High end of target range' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
analysis: {
|
||||
type: 'json',
|
||||
description: 'Analysis breakdown by category',
|
||||
properties: {
|
||||
breakdown: {
|
||||
type: 'json',
|
||||
description: 'Array of scoring breakdowns',
|
||||
properties: {
|
||||
title: { type: 'string', description: 'Category title' },
|
||||
weight: { type: 'number', description: 'Category weight' },
|
||||
score: { type: 'number', description: 'Category score' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
recommendations: {
|
||||
type: 'json',
|
||||
description: 'Content optimization recommendations',
|
||||
properties: {
|
||||
title: { type: 'string', description: 'Recommendation title' },
|
||||
status: { type: 'string', description: 'Status: done or pending' },
|
||||
impact: { type: 'json', description: 'Impact details with section and score' },
|
||||
suggestion: {
|
||||
type: 'json',
|
||||
description: 'Suggestion text and rationale',
|
||||
properties: {
|
||||
text: { type: 'string', description: 'Suggestion text' },
|
||||
rationale: { type: 'string', description: 'Why this recommendation matters' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundPromptAnswersParams, ProfoundPromptAnswersResponse } from './types'
|
||||
|
||||
export const profoundPromptAnswersTool: ToolConfig<
|
||||
ProfoundPromptAnswersParams,
|
||||
ProfoundPromptAnswersResponse
|
||||
> = {
|
||||
id: 'profound_prompt_answers',
|
||||
name: 'Profound Prompt Answers',
|
||||
description: 'Get raw prompt answers data for a category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"prompt_type","operator":"is","value":"visibility"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/prompts/answers',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
category_id: params.categoryId,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to get prompt answers')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map(
|
||||
(row: {
|
||||
prompt: string | null
|
||||
prompt_type: string | null
|
||||
response: string | null
|
||||
mentions: string[] | null
|
||||
citations: string[] | null
|
||||
topic: string | null
|
||||
region: string | null
|
||||
model: string | null
|
||||
asset: string | null
|
||||
created_at: string | null
|
||||
}) => ({
|
||||
prompt: row.prompt ?? null,
|
||||
promptType: row.prompt_type ?? null,
|
||||
response: row.response ?? null,
|
||||
mentions: row.mentions ?? [],
|
||||
citations: row.citations ?? [],
|
||||
topic: row.topic ?? null,
|
||||
region: row.region ?? null,
|
||||
model: row.model ?? null,
|
||||
asset: row.asset ?? null,
|
||||
createdAt: row.created_at ?? null,
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of answer rows',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Raw prompt answer data',
|
||||
properties: {
|
||||
prompt: { type: 'string', description: 'The prompt text' },
|
||||
promptType: { type: 'string', description: 'Prompt type (visibility or sentiment)' },
|
||||
response: { type: 'string', description: 'AI model response text' },
|
||||
mentions: { type: 'json', description: 'Companies/assets mentioned in the response' },
|
||||
citations: { type: 'json', description: 'URLs cited in the response' },
|
||||
topic: { type: 'string', description: 'Topic name' },
|
||||
region: { type: 'string', description: 'Region name' },
|
||||
model: { type: 'string', description: 'AI model/platform name' },
|
||||
asset: { type: 'string', description: 'Asset name' },
|
||||
createdAt: { type: 'string', description: 'Timestamp when the answer was collected' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundPromptVolumeParams, ProfoundPromptVolumeResponse } from './types'
|
||||
|
||||
export const profoundPromptVolumeTool: ToolConfig<
|
||||
ProfoundPromptVolumeParams,
|
||||
ProfoundPromptVolumeResponse
|
||||
> = {
|
||||
id: 'profound_prompt_volume',
|
||||
name: 'Profound Prompt Volume',
|
||||
description:
|
||||
'Query prompt volume data to understand search demand across AI platforms in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: volume, change',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: keyword, date, platform, country_code, matching_type, frequency',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"keyword","operator":"contains","value":"best"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/prompt-volumes/volume',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query prompt volume')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Volume data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundQueryFanoutsParams, ProfoundQueryFanoutsResponse } from './types'
|
||||
|
||||
export const profoundQueryFanoutsTool: ToolConfig<
|
||||
ProfoundQueryFanoutsParams,
|
||||
ProfoundQueryFanoutsResponse
|
||||
> = {
|
||||
id: 'profound_query_fanouts',
|
||||
name: 'Profound Query Fanouts',
|
||||
description:
|
||||
'Query fanout report showing how AI models expand prompts into sub-queries in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: fanouts_per_execution, total_fanouts, share',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated dimensions: prompt, query, model, region, date',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON array of filter objects',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/reports/query-fanouts',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
category_id: params.categoryId,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query fanouts report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundRawLogsParams, ProfoundRawLogsResponse } from './types'
|
||||
|
||||
export const profoundRawLogsTool: ToolConfig<ProfoundRawLogsParams, ProfoundRawLogsResponse> = {
|
||||
id: 'profound_raw_logs',
|
||||
name: 'Profound Raw Logs',
|
||||
description: 'Get raw traffic logs with filters for a domain in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to query logs for (e.g. example.com)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601). Defaults to now',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: timestamp, method, host, path, status_code, ip, user_agent, referer, bytes_sent, duration_ms, query_params',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"path","operator":"contains","value":"/blog"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/logs/raw',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
domain: params.domain,
|
||||
start_date: params.startDate,
|
||||
metrics: ['count'],
|
||||
}
|
||||
if (params.endDate) {
|
||||
body.end_date = params.endDate
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to get raw logs')
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.length,
|
||||
data: data.map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of log entries',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Log data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: { type: 'json', description: 'Array of metric values (count)' },
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundReferralsReportParams, ProfoundReferralsReportResponse } from './types'
|
||||
|
||||
export const profoundReferralsReportTool: ToolConfig<
|
||||
ProfoundReferralsReportParams,
|
||||
ProfoundReferralsReportResponse
|
||||
> = {
|
||||
id: 'profound_referrals_report',
|
||||
name: 'Profound Referrals Report',
|
||||
description:
|
||||
'Query human referral traffic report with hourly granularity for a domain in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to query referral traffic for (e.g. example.com)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601). Defaults to now',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: visits, last_visit',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated dimensions: date, hour, path, referral_source, referral_type',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"referral_source","operator":"is","value":"openai"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v2/reports/referrals',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
domain: params.domain,
|
||||
start_date: params.startDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.endDate) {
|
||||
body.end_date = params.endDate
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query referrals report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundSentimentReportParams, ProfoundSentimentReportResponse } from './types'
|
||||
|
||||
export const profoundSentimentReportTool: ToolConfig<
|
||||
ProfoundSentimentReportParams,
|
||||
ProfoundSentimentReportResponse
|
||||
> = {
|
||||
id: 'profound_sentiment_report',
|
||||
name: 'Profound Sentiment Report',
|
||||
description: 'Query sentiment report for a category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated metrics: positive, negative, occurrences',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: theme, date, region, topic, model, asset_name, tag, prompt, sentiment_type, persona',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"asset_name","operator":"is","value":"Company"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/reports/sentiment',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
category_id: params.categoryId,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query sentiment report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
/** Shared report response shape (visibility, sentiment, citations, bots, referrals, query fanouts, prompt volume) */
|
||||
interface ProfoundReportResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
data: Array<{
|
||||
metrics: number[]
|
||||
dimensions: string[]
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
/** Shared report query params for category-based reports */
|
||||
interface ProfoundCategoryReportParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
startDate: string
|
||||
endDate: string
|
||||
metrics: string
|
||||
dimensions?: string
|
||||
dateInterval?: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
/** Shared report query params for domain-based reports */
|
||||
interface ProfoundDomainReportParams {
|
||||
apiKey: string
|
||||
domain: string
|
||||
startDate: string
|
||||
endDate?: string
|
||||
metrics: string
|
||||
dimensions?: string
|
||||
dateInterval?: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
// --- Organization endpoints ---
|
||||
|
||||
export interface ProfoundListCategoriesParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListCategoriesResponse extends ToolResponse {
|
||||
output: {
|
||||
categories: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundListRegionsParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListRegionsResponse extends ToolResponse {
|
||||
output: {
|
||||
regions: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundListModelsParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListModelsResponse extends ToolResponse {
|
||||
output: {
|
||||
models: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundListDomainsParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListDomainsResponse extends ToolResponse {
|
||||
output: {
|
||||
domains: Array<{
|
||||
id: string
|
||||
name: string
|
||||
createdAt: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundListAssetsParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListAssetsResponse extends ToolResponse {
|
||||
output: {
|
||||
assets: Array<{
|
||||
id: string
|
||||
name: string
|
||||
website: string
|
||||
alternateDomains: string[] | null
|
||||
isOwned: boolean
|
||||
createdAt: string
|
||||
logoUrl: string
|
||||
categoryId: string
|
||||
categoryName: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundListPersonasParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface ProfoundListPersonasResponse extends ToolResponse {
|
||||
output: {
|
||||
personas: Array<{
|
||||
id: string
|
||||
name: string
|
||||
categoryId: string
|
||||
categoryName: string
|
||||
persona: {
|
||||
behavior: { painPoints: string | null; motivations: string | null }
|
||||
employment: {
|
||||
industry: string[]
|
||||
jobTitle: string[]
|
||||
companySize: string[]
|
||||
roleSeniority: string[]
|
||||
}
|
||||
demographics: { ageRange: string[] }
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
// --- Category-specific endpoints ---
|
||||
|
||||
export interface ProfoundCategoryTopicsParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryTopicsResponse extends ToolResponse {
|
||||
output: {
|
||||
topics: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryTagsParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryTagsResponse extends ToolResponse {
|
||||
output: {
|
||||
tags: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryPromptsParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
limit?: number
|
||||
cursor?: string
|
||||
orderDir?: string
|
||||
promptType?: string
|
||||
topicId?: string
|
||||
tagId?: string
|
||||
regionId?: string
|
||||
platformId?: string
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryPromptsResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
nextCursor: string | null
|
||||
prompts: Array<{
|
||||
id: string
|
||||
prompt: string
|
||||
promptType: string
|
||||
topicId: string
|
||||
topicName: string
|
||||
tags: Array<{ id: string; name: string }>
|
||||
regions: Array<{ id: string; name: string }>
|
||||
platforms: Array<{ id: string; name: string }>
|
||||
createdAt: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryAssetsParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryAssetsResponse extends ToolResponse {
|
||||
output: {
|
||||
assets: Array<{
|
||||
id: string
|
||||
name: string
|
||||
website: string
|
||||
alternateDomains: string[] | null
|
||||
isOwned: boolean
|
||||
createdAt: string
|
||||
logoUrl: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryPersonasParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
}
|
||||
|
||||
export interface ProfoundCategoryPersonasResponse extends ToolResponse {
|
||||
output: {
|
||||
personas: Array<{
|
||||
id: string
|
||||
name: string
|
||||
persona: {
|
||||
behavior: { painPoints: string | null; motivations: string | null }
|
||||
employment: {
|
||||
industry: string[]
|
||||
jobTitle: string[]
|
||||
companySize: string[]
|
||||
roleSeniority: string[]
|
||||
}
|
||||
demographics: { ageRange: string[] }
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
// --- Reports ---
|
||||
|
||||
export type ProfoundVisibilityReportParams = ProfoundCategoryReportParams
|
||||
export type ProfoundVisibilityReportResponse = ProfoundReportResponse
|
||||
|
||||
export type ProfoundSentimentReportParams = ProfoundCategoryReportParams
|
||||
export type ProfoundSentimentReportResponse = ProfoundReportResponse
|
||||
|
||||
export type ProfoundCitationsReportParams = ProfoundCategoryReportParams
|
||||
export type ProfoundCitationsReportResponse = ProfoundReportResponse
|
||||
|
||||
export type ProfoundQueryFanoutsParams = ProfoundCategoryReportParams
|
||||
export type ProfoundQueryFanoutsResponse = ProfoundReportResponse
|
||||
|
||||
export type ProfoundBotsReportParams = ProfoundDomainReportParams
|
||||
export type ProfoundBotsReportResponse = ProfoundReportResponse
|
||||
|
||||
export type ProfoundReferralsReportParams = ProfoundDomainReportParams
|
||||
export type ProfoundReferralsReportResponse = ProfoundReportResponse
|
||||
|
||||
// --- Prompts ---
|
||||
|
||||
export interface ProfoundPromptAnswersParams {
|
||||
apiKey: string
|
||||
categoryId: string
|
||||
startDate: string
|
||||
endDate: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface ProfoundPromptAnswersResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
data: Array<{
|
||||
prompt: string | null
|
||||
promptType: string | null
|
||||
response: string | null
|
||||
mentions: string[] | null
|
||||
citations: string[] | null
|
||||
topic: string | null
|
||||
region: string | null
|
||||
model: string | null
|
||||
asset: string | null
|
||||
createdAt: string | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
// --- Agent Analytics ---
|
||||
|
||||
export interface ProfoundRawLogsParams {
|
||||
apiKey: string
|
||||
domain: string
|
||||
startDate: string
|
||||
endDate?: string
|
||||
dimensions?: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface ProfoundRawLogsResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
data: Array<{
|
||||
metrics: number[]
|
||||
dimensions: string[]
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundBotLogsParams {
|
||||
apiKey: string
|
||||
domain: string
|
||||
startDate: string
|
||||
endDate?: string
|
||||
dimensions?: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface ProfoundBotLogsResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
data: Array<{
|
||||
metrics: number[]
|
||||
dimensions: string[]
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
// --- Content ---
|
||||
|
||||
export interface ProfoundListOptimizationsParams {
|
||||
apiKey: string
|
||||
assetId: string
|
||||
limit?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
export interface ProfoundListOptimizationsResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
optimizations: Array<{
|
||||
id: string
|
||||
title: string
|
||||
createdAt: string
|
||||
extractedInput: string | null
|
||||
type: string
|
||||
status: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundOptimizationAnalysisParams {
|
||||
apiKey: string
|
||||
assetId: string
|
||||
contentId: string
|
||||
}
|
||||
|
||||
export interface ProfoundOptimizationAnalysisResponse extends ToolResponse {
|
||||
output: {
|
||||
content: {
|
||||
format: string
|
||||
value: string
|
||||
}
|
||||
aeoContentScore: {
|
||||
value: number
|
||||
targetZone: { low: number; high: number }
|
||||
} | null
|
||||
analysis: {
|
||||
breakdown: Array<{
|
||||
title: string
|
||||
weight: number
|
||||
score: number
|
||||
}>
|
||||
}
|
||||
recommendations: Array<{
|
||||
title: string
|
||||
status: string
|
||||
impact: { section: string; score: number } | null
|
||||
suggestion: { text: string; rationale: string }
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
// --- Prompt Volumes ---
|
||||
|
||||
export interface ProfoundPromptVolumeParams {
|
||||
apiKey: string
|
||||
startDate: string
|
||||
endDate: string
|
||||
metrics: string
|
||||
dimensions?: string
|
||||
dateInterval?: string
|
||||
filters?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface ProfoundPromptVolumeResponse extends ToolResponse {
|
||||
output: {
|
||||
totalRows: number
|
||||
data: Array<{
|
||||
metrics: number[]
|
||||
dimensions: string[]
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfoundCitationPromptsParams {
|
||||
apiKey: string
|
||||
inputDomain: string
|
||||
}
|
||||
|
||||
export interface ProfoundCitationPromptsResponse extends ToolResponse {
|
||||
output: {
|
||||
data: unknown
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ProfoundVisibilityReportParams, ProfoundVisibilityReportResponse } from './types'
|
||||
|
||||
export const profoundVisibilityReportTool: ToolConfig<
|
||||
ProfoundVisibilityReportParams,
|
||||
ProfoundVisibilityReportResponse
|
||||
> = {
|
||||
id: 'profound_visibility_report',
|
||||
name: 'Profound Visibility Report',
|
||||
description: 'Query AI visibility report for a category in Profound',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Profound API Key',
|
||||
},
|
||||
categoryId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category ID (UUID)',
|
||||
},
|
||||
startDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
endDate: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'End date (YYYY-MM-DD or ISO 8601)',
|
||||
},
|
||||
metrics: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated metrics: share_of_voice, mentions_count, visibility_score, executions, average_position',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated dimensions: date, region, topic, model, asset_name, prompt, tag, persona',
|
||||
},
|
||||
dateInterval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Date interval: hour, day, week, month, year',
|
||||
},
|
||||
filters: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of filter objects, e.g. [{"field":"asset_name","operator":"is","value":"Company"}]',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (default 10000, max 50000)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tryprofound.com/v1/reports/visibility',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'X-API-Key': params.apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
category_id: params.categoryId,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
metrics: params.metrics.split(',').map((m) => m.trim()),
|
||||
}
|
||||
if (params.dimensions) {
|
||||
body.dimensions = params.dimensions.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.dateInterval) {
|
||||
body.date_interval = params.dateInterval
|
||||
}
|
||||
if (params.filters) {
|
||||
try {
|
||||
body.filters = JSON.parse(params.filters)
|
||||
} catch {
|
||||
throw new Error('Invalid JSON in filters parameter')
|
||||
}
|
||||
}
|
||||
if (params.limit != null) {
|
||||
body.pagination = { limit: params.limit }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
throw new Error(data.detail?.[0]?.msg || 'Failed to query visibility report')
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
totalRows: data.info?.total_rows ?? 0,
|
||||
data: (data.data ?? []).map((row: { metrics: number[]; dimensions: string[] }) => ({
|
||||
metrics: row.metrics ?? [],
|
||||
dimensions: row.dimensions ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
totalRows: {
|
||||
type: 'number',
|
||||
description: 'Total number of rows in the report',
|
||||
},
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Report data rows with metrics and dimension values',
|
||||
properties: {
|
||||
metrics: {
|
||||
type: 'json',
|
||||
description: 'Array of metric values matching requested metrics order',
|
||||
},
|
||||
dimensions: {
|
||||
type: 'json',
|
||||
description: 'Array of dimension values matching requested dimensions order',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user