From e52fe77100e71fc5954f2e6b3ccc0164fb96255d Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Jul 2026 12:07:32 -0700 Subject: [PATCH 1/5] feat(flint): add Flint integration with agent task tools, block, and docs --- apps/docs/components/icons.tsx | 16 + apps/docs/components/ui/icon-mapping.ts | 2 + .../content/docs/en/integrations/flint.mdx | 85 +++++ .../content/docs/en/integrations/meta.json | 1 + apps/sim/blocks/blocks/flint.ts | 298 ++++++++++++++++++ apps/sim/blocks/registry-maps.ts | 3 + apps/sim/components/icons.tsx | 16 + apps/sim/lib/integrations/icon-mapping.ts | 2 + apps/sim/lib/integrations/integrations.json | 33 +- apps/sim/tools/flint/create_task.ts | 72 +++++ apps/sim/tools/flint/generate_pages.ts | 127 ++++++++ apps/sim/tools/flint/get_task.ts | 100 ++++++ apps/sim/tools/flint/index.ts | 4 + apps/sim/tools/flint/types.ts | 70 ++++ apps/sim/tools/flint/utils.ts | 30 ++ apps/sim/tools/registry.ts | 4 + 16 files changed, 862 insertions(+), 1 deletion(-) create mode 100644 apps/docs/content/docs/en/integrations/flint.mdx create mode 100644 apps/sim/blocks/blocks/flint.ts create mode 100644 apps/sim/tools/flint/create_task.ts create mode 100644 apps/sim/tools/flint/generate_pages.ts create mode 100644 apps/sim/tools/flint/get_task.ts create mode 100644 apps/sim/tools/flint/index.ts create mode 100644 apps/sim/tools/flint/types.ts create mode 100644 apps/sim/tools/flint/utils.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 4c58dddc322..8633baa4cab 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -6827,6 +6827,22 @@ export function JiraServiceManagementIcon(props: SVGProps) { ) } +export function FlintIcon(props: SVGProps) { + return ( + + + + + + ) +} + export function FirefliesIcon(props: SVGProps) { const id = useId() const g1 = `fireflies_g1_${id}` diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 38effba830e..8c250bbf102 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -72,6 +72,7 @@ import { FindymailIcon, FirecrawlIcon, FirefliesIcon, + FlintIcon, GammaIcon, GithubIcon, GitLabIcon, @@ -315,6 +316,7 @@ export const blockTypeToIconMap: Record = { firecrawl: FirecrawlIcon, fireflies: FirefliesIcon, fireflies_v2: FirefliesIcon, + flint: FlintIcon, gamma: GammaIcon, github: GithubIcon, github_v2: GithubIcon, diff --git a/apps/docs/content/docs/en/integrations/flint.mdx b/apps/docs/content/docs/en/integrations/flint.mdx new file mode 100644 index 00000000000..25eb095995e --- /dev/null +++ b/apps/docs/content/docs/en/integrations/flint.mdx @@ -0,0 +1,85 @@ +--- +title: Flint +description: Run background agent tasks on your Flint sites +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Create background agent tasks that modify your Flint sites from natural-language prompts, generate batches of pages from a template, and check task status and results. + + + +## Actions + +### `flint_create_task` + +Start a background Flint agent task that modifies a site from a natural-language prompt. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `siteId` | string | Yes | ID of the Flint site the agent should modify | +| `prompt` | string | Yes | Natural-language instructions for the agent \(e.g., "Add a new About page with a team section"\) | +| `callbackUrl` | string | No | HTTPS webhook URL that Flint will POST to when the task completes or fails | +| `publish` | boolean | No | Whether to automatically publish the changes when the task completes | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `taskId` | string | Identifier of the created background task | +| `status` | string | Initial task status \(running\) | +| `createdAt` | string | ISO 8601 timestamp when the task was created | + +### `flint_generate_pages` + +Start a background Flint agent task that generates up to 10 pages from a template page. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `siteId` | string | Yes | ID of the Flint site the agent should modify | +| `templatePageSlug` | string | Yes | Slug of the existing template page to generate from \(e.g., /case-studies/template\) | +| `items` | json | Yes | JSON array of 1-10 pages to generate. Each item requires targetPageSlug \(slug for the new page\) and context \(content details the agent should use\). | +| `callbackUrl` | string | No | HTTPS webhook URL that Flint will POST to when the task completes or fails | +| `publish` | boolean | No | Whether to automatically publish the generated pages when the task completes | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `taskId` | string | Identifier of the created background task | +| `status` | string | Initial task status \(running\) | +| `createdAt` | string | ISO 8601 timestamp when the task was created | + +### `flint_get_task` + +Get the status and results of a background Flint agent task. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `taskId` | string | Yes | Identifier of the task returned when it was created \(e.g., bg-...\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `taskId` | string | Identifier of the task | +| `status` | string | Task status: running, completed, or failed | +| `pagesCreated` | array | Pages created by the task \(populated when completed\) | +| `pagesModified` | array | Pages modified by the task \(populated when completed\) | +| `pagesDeleted` | array | Pages deleted by the task \(populated when completed\) | +| `errorMessage` | string | Error message when the task failed | + + diff --git a/apps/docs/content/docs/en/integrations/meta.json b/apps/docs/content/docs/en/integrations/meta.json index 85ab2e676bc..421c63a7dfa 100644 --- a/apps/docs/content/docs/en/integrations/meta.json +++ b/apps/docs/content/docs/en/integrations/meta.json @@ -70,6 +70,7 @@ "findymail", "firecrawl", "fireflies", + "flint", "gamma", "github", "gitlab", diff --git a/apps/sim/blocks/blocks/flint.ts b/apps/sim/blocks/blocks/flint.ts new file mode 100644 index 00000000000..8495d0b4486 --- /dev/null +++ b/apps/sim/blocks/blocks/flint.ts @@ -0,0 +1,298 @@ +import { FlintIcon } from '@/components/icons' +import type { BlockConfig, BlockMeta } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' + +export const FlintBlock: BlockConfig = { + type: 'flint', + name: 'Flint', + description: 'Run background agent tasks on your Flint sites', + longDescription: + 'Create background agent tasks that modify your Flint sites from natural-language prompts, generate batches of pages from a template, and check task status and results.', + docsLink: 'https://docs.sim.ai/integrations/flint', + category: 'tools', + integrationType: IntegrationType.Marketing, + bgColor: '#F6F54F', + icon: FlintIcon, + authMode: AuthMode.ApiKey, + + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Create Task', id: 'flint_create_task' }, + { label: 'Generate Pages', id: 'flint_generate_pages' }, + { label: 'Get Task', id: 'flint_get_task' }, + ], + value: () => 'flint_create_task', + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + placeholder: 'Your Flint API key (ak_...)', + password: true, + required: true, + }, + { + id: 'siteId', + title: 'Site ID', + type: 'short-input', + placeholder: 'ID of the Flint site to modify', + condition: { + field: 'operation', + value: ['flint_create_task', 'flint_generate_pages'], + }, + required: { + field: 'operation', + value: ['flint_create_task', 'flint_generate_pages'], + }, + }, + { + id: 'prompt', + title: 'Prompt', + type: 'long-input', + placeholder: 'e.g. Add a new About page with a team section', + condition: { field: 'operation', value: 'flint_create_task' }, + required: { field: 'operation', value: 'flint_create_task' }, + }, + { + id: 'templatePageSlug', + title: 'Template Page Slug', + type: 'short-input', + placeholder: '/case-studies/template', + condition: { field: 'operation', value: 'flint_generate_pages' }, + required: { field: 'operation', value: 'flint_generate_pages' }, + }, + { + id: 'items', + title: 'Pages (JSON)', + type: 'code', + placeholder: `[ + { + "targetPageSlug": "/case-studies/acme-corp", + "context": "Company: Acme Corp. Industry: Manufacturing..." + } +]`, + condition: { field: 'operation', value: 'flint_generate_pages' }, + required: { field: 'operation', value: 'flint_generate_pages' }, + wandConfig: { + enabled: true, + prompt: `Generate a JSON array of pages to create from a Flint template based on the user's description. +Each page object must have exactly these fields: +- "targetPageSlug": The slug for the new page (e.g., "/case-studies/acme-corp") +- "context": Content details the agent should use to fill in the template + +The array must contain between 1 and 10 items. +Return ONLY valid JSON - no explanations, no markdown code blocks.`, + placeholder: 'Describe the pages you want to generate...', + generationType: 'json-object', + }, + }, + { + id: 'taskId', + title: 'Task ID', + type: 'short-input', + placeholder: 'The task ID returned when the task was created', + condition: { field: 'operation', value: 'flint_get_task' }, + required: { field: 'operation', value: 'flint_get_task' }, + }, + { + id: 'publish', + title: 'Publish on Completion', + type: 'switch', + mode: 'advanced', + condition: { + field: 'operation', + value: ['flint_create_task', 'flint_generate_pages'], + }, + }, + { + id: 'callbackUrl', + title: 'Callback URL', + type: 'short-input', + placeholder: 'https://your-server.com/webhooks/flint', + mode: 'advanced', + condition: { + field: 'operation', + value: ['flint_create_task', 'flint_generate_pages'], + }, + }, + ], + + tools: { + access: ['flint_create_task', 'flint_generate_pages', 'flint_get_task'], + config: { + tool: (params) => params.operation || 'flint_create_task', + params: (params) => { + const base: Record = { apiKey: params.apiKey } + + switch (params.operation) { + case 'flint_create_task': + return { + ...base, + siteId: params.siteId, + prompt: params.prompt, + callbackUrl: params.callbackUrl || undefined, + publish: params.publish === true || params.publish === 'true' ? true : undefined, + } + case 'flint_generate_pages': + return { + ...base, + siteId: params.siteId, + templatePageSlug: params.templatePageSlug, + items: params.items, + callbackUrl: params.callbackUrl || undefined, + publish: params.publish === true || params.publish === 'true' ? true : undefined, + } + case 'flint_get_task': + return { ...base, taskId: params.taskId } + default: + return base + } + }, + }, + }, + + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Flint API key' }, + siteId: { type: 'string', description: 'ID of the Flint site to modify' }, + prompt: { type: 'string', description: 'Natural-language instructions for the agent' }, + templatePageSlug: { + type: 'string', + description: 'Slug of the template page to generate from', + }, + items: { + type: 'json', + description: 'JSON array of 1-10 pages to generate, each with targetPageSlug and context', + }, + taskId: { type: 'string', description: 'Task ID to look up' }, + publish: { type: 'boolean', description: 'Publish changes automatically on completion' }, + callbackUrl: { type: 'string', description: 'HTTPS webhook URL notified on completion' }, + }, + + outputs: { + taskId: { type: 'string', description: 'Identifier of the background task' }, + status: { type: 'string', description: 'Task status: running, completed, or failed' }, + createdAt: { type: 'string', description: 'When the task was created' }, + pagesCreated: { + type: 'array', + description: 'Pages created by the task [{slug, previewUrl, editUrl, publishedUrl}]', + }, + pagesModified: { + type: 'array', + description: 'Pages modified by the task [{slug, previewUrl, editUrl, publishedUrl}]', + }, + pagesDeleted: { + type: 'array', + description: 'Pages deleted by the task [{slug, previewUrl, editUrl, publishedUrl}]', + }, + errorMessage: { type: 'string', description: 'Error message when the task failed' }, + }, +} + +export const FlintBlockMeta = { + tags: ['automation', 'seo', 'agentic'], + url: 'https://www.flint.com', + templates: [ + { + icon: FlintIcon, + title: 'Flint programmatic SEO pages', + prompt: + 'Build a workflow that reads a table of target keywords and customer data, then uses Flint to generate a landing page for each row from a template page, publishing them automatically.', + modules: ['tables', 'agent', 'workflows'], + category: 'marketing', + tags: ['seo', 'automation'], + }, + { + icon: FlintIcon, + title: 'Flint case-study generator', + prompt: + 'Create a workflow triggered when a deal is marked closed-won that pulls the customer details, drafts case-study context with an agent, and uses Flint to generate a case-study page from the template.', + modules: ['agent', 'workflows'], + category: 'marketing', + tags: ['seo', 'automation'], + alsoIntegrations: ['hubspot'], + }, + { + icon: FlintIcon, + title: 'Flint site update from Slack', + prompt: + 'Build a workflow triggered by a Slack message in the #website channel that turns the request into a Flint agent task prompt, starts the task, and replies in the thread with the task ID.', + modules: ['agent', 'workflows'], + category: 'marketing', + tags: ['automation'], + alsoIntegrations: ['slack'], + }, + { + icon: FlintIcon, + title: 'Flint task status monitor', + prompt: + 'Create a scheduled workflow that reads pending Flint task IDs from a table, checks each task status with Flint, writes preview and published URLs back to the row when completed, and flags failures.', + modules: ['scheduled', 'tables', 'workflows'], + category: 'operations', + tags: ['automation', 'monitoring'], + }, + { + icon: FlintIcon, + title: 'Flint changelog page publisher', + prompt: + 'Build a workflow triggered when a new release is tagged in GitHub that summarizes the changes with an agent and starts a Flint task to add the release notes to the changelog page, publishing on completion.', + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['automation'], + alsoIntegrations: ['github'], + }, + { + icon: FlintIcon, + title: 'Flint failed-task alerts', + prompt: + 'Create a workflow that checks a Flint task status and, when the task has failed, posts the task ID and error message to a Slack channel so the team can rerun it.', + modules: ['agent', 'workflows'], + category: 'operations', + tags: ['automation', 'incident-management'], + alsoIntegrations: ['slack'], + }, + { + icon: FlintIcon, + title: 'Flint location pages from a spreadsheet', + prompt: + 'Build a workflow that reads city and service data from Google Sheets and uses Flint to generate a local landing page per city from a template, then writes each published URL back to the sheet.', + modules: ['agent', 'workflows'], + category: 'marketing', + tags: ['seo', 'automation'], + alsoIntegrations: ['google_sheets'], + }, + { + icon: FlintIcon, + title: 'Flint content refresh agent', + prompt: + 'Create a scheduled workflow that reviews outdated pages listed in a table, drafts updated copy instructions with an agent, and starts a Flint task per page to refresh the content without publishing until reviewed.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'marketing', + tags: ['seo', 'automation'], + }, + ], + skills: [ + { + name: 'run-flint-site-update', + description: 'Start a Flint agent task from a prompt and track it to completion.', + content: + '# Run a Flint Site Update\n\nModify a Flint site with a natural-language prompt.\n\n## Steps\n1. Choose the Create Task operation.\n2. Enter the Site ID and write a clear Prompt describing the change (for example "Add a new About page with a team section").\n3. Optionally enable Publish on Completion to push the change live automatically.\n4. Save the returned taskId, then poll with the Get Task operation until status is completed or failed.\n\n## Output\nReturn the task status and, when completed, the created/modified pages with their preview, edit, and published URLs.', + }, + { + name: 'generate-pages-from-template', + description: 'Generate up to 10 Flint pages from a template page in one task.', + content: + '# Generate Pages from a Template\n\nCreate a batch of pages that share a template layout.\n\n## Steps\n1. Choose the Generate Pages operation.\n2. Enter the Site ID and the Template Page Slug of the existing template (for example /case-studies/template).\n3. Provide the Pages JSON array with 1-10 items, each containing targetPageSlug and context.\n4. Poll the task with Get Task until it completes.\n\n## Output\nReturn the list of created pages with their slugs and preview, edit, and published URLs.', + }, + { + name: 'check-flint-task-status', + description: 'Check whether a Flint agent task is running, completed, or failed.', + content: + '# Check a Flint Task\n\nLook up the state and results of a background task.\n\n## Steps\n1. Choose the Get Task operation.\n2. Enter the Task ID returned when the task was created.\n3. Branch on the returned status: running means keep polling, completed exposes pagesCreated/pagesModified/pagesDeleted, failed exposes errorMessage.\n\n## Output\nReturn the task status plus page URLs on success or the error message on failure.', + }, + ], +} as const satisfies BlockMeta diff --git a/apps/sim/blocks/registry-maps.ts b/apps/sim/blocks/registry-maps.ts index 7934e50a8f1..31a695b6f2f 100644 --- a/apps/sim/blocks/registry-maps.ts +++ b/apps/sim/blocks/registry-maps.ts @@ -78,6 +78,7 @@ import { FirefliesV2Block, FirefliesV2BlockMeta, } from '@/blocks/blocks/fireflies' +import { FlintBlock, FlintBlockMeta } from '@/blocks/blocks/flint' import { FunctionBlock } from '@/blocks/blocks/function' import { GammaBlock, GammaBlockMeta } from '@/blocks/blocks/gamma' import { GenericWebhookBlock } from '@/blocks/blocks/generic_webhook' @@ -422,6 +423,7 @@ export const BLOCK_REGISTRY: Record = { firecrawl: FirecrawlBlock, fireflies: FirefliesBlock, fireflies_v2: FirefliesV2Block, + flint: FlintBlock, function: FunctionBlock, gamma: GammaBlock, generic_webhook: GenericWebhookBlock, @@ -724,6 +726,7 @@ export const BLOCK_META_REGISTRY: Record = { firecrawl: FirecrawlBlockMeta, fireflies: FirefliesBlockMeta, fireflies_v2: FirefliesV2BlockMeta, + flint: FlintBlockMeta, gamma: GammaBlockMeta, github: GitHubBlockMeta, github_v2: GitHubV2BlockMeta, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index f1fb7446eeb..79c5e54b477 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -6859,6 +6859,22 @@ export function JiraServiceManagementIcon(props: SVGProps) { ) } +export function FlintIcon(props: SVGProps) { + return ( + + + + + + ) +} + export function FirefliesIcon(props: SVGProps) { const id = useId() const g1 = `fireflies_g1_${id}` diff --git a/apps/sim/lib/integrations/icon-mapping.ts b/apps/sim/lib/integrations/icon-mapping.ts index f7c5ddf8d19..ef098c5a025 100644 --- a/apps/sim/lib/integrations/icon-mapping.ts +++ b/apps/sim/lib/integrations/icon-mapping.ts @@ -71,6 +71,7 @@ import { FindymailIcon, FirecrawlIcon, FirefliesIcon, + FlintIcon, GammaIcon, GithubIcon, GitLabIcon, @@ -306,6 +307,7 @@ export const blockTypeToIconMap: Record = { findymail: FindymailIcon, firecrawl: FirecrawlIcon, fireflies_v2: FirefliesIcon, + flint: FlintIcon, gamma: GammaIcon, github_v2: GithubIcon, gitlab: GitLabIcon, diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index b077fd0747d..b9640849822 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1,5 +1,5 @@ { - "updatedAt": "2026-07-11", + "updatedAt": "2026-07-13", "integrations": [ { "type": "onepassword", @@ -5729,6 +5729,37 @@ "integrationType": "productivity", "tags": ["meeting", "note-taking"] }, + { + "type": "flint", + "slug": "flint", + "name": "Flint", + "description": "Run background agent tasks on your Flint sites", + "longDescription": "Create background agent tasks that modify your Flint sites from natural-language prompts, generate batches of pages from a template, and check task status and results.", + "bgColor": "#F6F54F", + "iconName": "FlintIcon", + "docsUrl": "https://docs.sim.ai/integrations/flint", + "operations": [ + { + "name": "Create Task", + "description": "Start a background Flint agent task that modifies a site from a natural-language prompt." + }, + { + "name": "Generate Pages", + "description": "Start a background Flint agent task that generates up to 10 pages from a template page." + }, + { + "name": "Get Task", + "description": "Get the status and results of a background Flint agent task." + } + ], + "operationCount": 3, + "triggers": [], + "triggerCount": 0, + "authType": "api-key", + "category": "tools", + "integrationType": "marketing", + "tags": ["automation", "seo", "agentic"] + }, { "type": "gamma", "slug": "gamma", diff --git a/apps/sim/tools/flint/create_task.ts b/apps/sim/tools/flint/create_task.ts new file mode 100644 index 00000000000..704a4db2d59 --- /dev/null +++ b/apps/sim/tools/flint/create_task.ts @@ -0,0 +1,72 @@ +import { filterUndefined } from '@sim/utils/object' +import type { FlintCreateTaskParams, FlintCreateTaskResponse } from '@/tools/flint/types' +import { FLINT_API_BASE_URL, flintBaseParamFields, flintHeaders } from '@/tools/flint/utils' +import type { ToolConfig } from '@/tools/types' + +export const flintCreateTaskTool: ToolConfig = { + id: 'flint_create_task', + name: 'Flint Create Task', + description: + 'Start a background Flint agent task that modifies a site from a natural-language prompt.', + version: '1.0.0', + + params: { + ...flintBaseParamFields, + siteId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the Flint site the agent should modify', + }, + prompt: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Natural-language instructions for the agent (e.g., "Add a new About page with a team section")', + }, + callbackUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'HTTPS webhook URL that Flint will POST to when the task completes or fails', + }, + publish: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to automatically publish the changes when the task completes', + }, + }, + + request: { + url: `${FLINT_API_BASE_URL}/agent/tasks`, + method: 'POST', + headers: (params) => flintHeaders(params), + body: (params) => + filterUndefined({ + siteId: params.siteId, + prompt: params.prompt, + callbackUrl: params.callbackUrl, + publish: params.publish, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + taskId: data.taskId ?? null, + status: data.status ?? null, + createdAt: data.createdAt ?? null, + }, + } + }, + + outputs: { + taskId: { type: 'string', description: 'Identifier of the created background task' }, + status: { type: 'string', description: 'Initial task status (running)' }, + createdAt: { type: 'string', description: 'ISO 8601 timestamp when the task was created' }, + }, +} diff --git a/apps/sim/tools/flint/generate_pages.ts b/apps/sim/tools/flint/generate_pages.ts new file mode 100644 index 00000000000..521c4b01557 --- /dev/null +++ b/apps/sim/tools/flint/generate_pages.ts @@ -0,0 +1,127 @@ +import { filterUndefined } from '@sim/utils/object' +import type { + FlintGeneratePagesItem, + FlintGeneratePagesParams, + FlintGeneratePagesResponse, +} from '@/tools/flint/types' +import { FLINT_API_BASE_URL, flintBaseParamFields, flintHeaders } from '@/tools/flint/utils' +import type { ToolConfig } from '@/tools/types' + +const MAX_ITEMS = 10 + +/** + * Parses and validates the items input, which may arrive as a JSON string + * from the block's code input or as an already-structured array. + */ +function parseItems(input: FlintGeneratePagesItem[] | string): FlintGeneratePagesItem[] { + let items: unknown + try { + items = typeof input === 'string' ? JSON.parse(input) : input + } catch { + throw new Error('Invalid JSON in items parameter') + } + if (!Array.isArray(items) || items.length === 0) { + throw new Error('items must be a non-empty JSON array of { targetPageSlug, context } objects') + } + if (items.length > MAX_ITEMS) { + throw new Error(`items supports at most ${MAX_ITEMS} pages per task`) + } + for (const item of items) { + if ( + typeof item !== 'object' || + item === null || + typeof (item as FlintGeneratePagesItem).targetPageSlug !== 'string' || + typeof (item as FlintGeneratePagesItem).context !== 'string' + ) { + throw new Error('Each item must include string targetPageSlug and context fields') + } + } + return items as FlintGeneratePagesItem[] +} + +export const flintGeneratePagesTool: ToolConfig< + FlintGeneratePagesParams, + FlintGeneratePagesResponse +> = { + id: 'flint_generate_pages', + name: 'Flint Generate Pages', + description: + 'Start a background Flint agent task that generates up to 10 pages from a template page.', + version: '1.0.0', + + params: { + ...flintBaseParamFields, + siteId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the Flint site the agent should modify', + }, + templatePageSlug: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Slug of the existing template page to generate from (e.g., /case-studies/template)', + }, + items: { + type: 'json', + required: true, + visibility: 'user-or-llm', + description: + 'JSON array of 1-10 pages to generate. Each item requires targetPageSlug (slug for the new page) and context (content details the agent should use).', + items: { + type: 'object', + properties: { + targetPageSlug: { type: 'string', description: 'Slug for the generated page' }, + context: { type: 'string', description: 'Content context for the generated page' }, + }, + }, + }, + callbackUrl: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'HTTPS webhook URL that Flint will POST to when the task completes or fails', + }, + publish: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to automatically publish the generated pages when the task completes', + }, + }, + + request: { + url: `${FLINT_API_BASE_URL}/agent/tasks`, + method: 'POST', + headers: (params) => flintHeaders(params), + body: (params) => + filterUndefined({ + siteId: params.siteId, + command: 'generate_pages', + templatePageSlug: params.templatePageSlug, + items: parseItems(params.items), + callbackUrl: params.callbackUrl, + publish: params.publish, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + taskId: data.taskId ?? null, + status: data.status ?? null, + createdAt: data.createdAt ?? null, + }, + } + }, + + outputs: { + taskId: { type: 'string', description: 'Identifier of the created background task' }, + status: { type: 'string', description: 'Initial task status (running)' }, + createdAt: { type: 'string', description: 'ISO 8601 timestamp when the task was created' }, + }, +} diff --git a/apps/sim/tools/flint/get_task.ts b/apps/sim/tools/flint/get_task.ts new file mode 100644 index 00000000000..8778e1be899 --- /dev/null +++ b/apps/sim/tools/flint/get_task.ts @@ -0,0 +1,100 @@ +import type { FlintGetTaskParams, FlintGetTaskResponse, FlintTaskPage } from '@/tools/flint/types' +import { FLINT_API_BASE_URL, flintBaseParamFields, flintHeaders } from '@/tools/flint/utils' +import type { ToolConfig } from '@/tools/types' + +const PAGE_OUTPUT_PROPERTIES = { + slug: { type: 'string', description: 'Page slug (e.g., /about)' }, + previewUrl: { + type: 'string', + description: 'Preview deployment URL for the page', + nullable: true, + }, + editUrl: { type: 'string', description: 'Flint editor URL for the page', nullable: true }, + publishedUrl: { + type: 'string', + description: 'Published URL on the live domain (present when publish is enabled)', + nullable: true, + }, +} as const + +/** + * Normalizes a page entry from the Flint API into a fully nullable page object. + */ +function toTaskPage(page: Record | null | undefined): FlintTaskPage { + return { + slug: typeof page?.slug === 'string' ? page.slug : null, + previewUrl: typeof page?.previewUrl === 'string' ? page.previewUrl : null, + editUrl: typeof page?.editUrl === 'string' ? page.editUrl : null, + publishedUrl: typeof page?.publishedUrl === 'string' ? page.publishedUrl : null, + } +} + +export const flintGetTaskTool: ToolConfig = { + id: 'flint_get_task', + name: 'Flint Get Task', + description: 'Get the status and results of a background Flint agent task.', + version: '1.0.0', + + params: { + ...flintBaseParamFields, + taskId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Identifier of the task returned when it was created (e.g., bg-...)', + }, + }, + + request: { + url: (params) => + `${FLINT_API_BASE_URL}/agent/tasks/${encodeURIComponent(params.taskId.trim())}`, + method: 'GET', + headers: (params) => flintHeaders(params), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + taskId: data.taskId ?? null, + status: data.status ?? null, + pagesCreated: Array.isArray(data.output?.pagesCreated) + ? data.output.pagesCreated.map(toTaskPage) + : [], + pagesModified: Array.isArray(data.output?.pagesModified) + ? data.output.pagesModified.map(toTaskPage) + : [], + pagesDeleted: Array.isArray(data.output?.pagesDeleted) + ? data.output.pagesDeleted.map(toTaskPage) + : [], + errorMessage: data.errorMessage ?? null, + }, + } + }, + + outputs: { + taskId: { type: 'string', description: 'Identifier of the task' }, + status: { type: 'string', description: 'Task status: running, completed, or failed' }, + pagesCreated: { + type: 'array', + description: 'Pages created by the task (populated when completed)', + items: { type: 'object', properties: PAGE_OUTPUT_PROPERTIES }, + }, + pagesModified: { + type: 'array', + description: 'Pages modified by the task (populated when completed)', + items: { type: 'object', properties: PAGE_OUTPUT_PROPERTIES }, + }, + pagesDeleted: { + type: 'array', + description: 'Pages deleted by the task (populated when completed)', + items: { type: 'object', properties: PAGE_OUTPUT_PROPERTIES }, + }, + errorMessage: { + type: 'string', + description: 'Error message when the task failed', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/flint/index.ts b/apps/sim/tools/flint/index.ts new file mode 100644 index 00000000000..d193d810cb0 --- /dev/null +++ b/apps/sim/tools/flint/index.ts @@ -0,0 +1,4 @@ +export { flintCreateTaskTool } from '@/tools/flint/create_task' +export { flintGeneratePagesTool } from '@/tools/flint/generate_pages' +export { flintGetTaskTool } from '@/tools/flint/get_task' +export * from '@/tools/flint/types' diff --git a/apps/sim/tools/flint/types.ts b/apps/sim/tools/flint/types.ts new file mode 100644 index 00000000000..f6fa7320df6 --- /dev/null +++ b/apps/sim/tools/flint/types.ts @@ -0,0 +1,70 @@ +import type { ToolResponse } from '@/tools/types' + +export interface FlintBaseParams { + apiKey: string +} + +export interface FlintCreateTaskParams extends FlintBaseParams { + siteId: string + prompt: string + callbackUrl?: string + publish?: boolean +} + +/** + * One page to generate when running a `generate_pages` task. + */ +export interface FlintGeneratePagesItem { + targetPageSlug: string + context: string +} + +export interface FlintGeneratePagesParams extends FlintBaseParams { + siteId: string + templatePageSlug: string + items: FlintGeneratePagesItem[] | string + callbackUrl?: string + publish?: boolean +} + +export interface FlintGetTaskParams extends FlintBaseParams { + taskId: string +} + +/** + * Page reference returned by Flint for created, modified, and deleted pages. + */ +export interface FlintTaskPage { + slug: string | null + previewUrl: string | null + editUrl: string | null + publishedUrl: string | null +} + +/** + * Shared output shape of the two task-creation endpoints. + */ +export interface FlintTaskCreatedOutput { + taskId: string | null + status: string | null + createdAt: string | null +} + +export interface FlintCreateTaskResponse extends ToolResponse { + output: FlintTaskCreatedOutput +} + +export interface FlintGeneratePagesResponse extends ToolResponse { + output: FlintTaskCreatedOutput +} + +export interface FlintGetTaskResponse extends ToolResponse { + output: { + taskId: string | null + status: string | null + pagesCreated: FlintTaskPage[] + pagesModified: FlintTaskPage[] + pagesDeleted: FlintTaskPage[] + errorMessage: string | null + } +} diff --git a/apps/sim/tools/flint/utils.ts b/apps/sim/tools/flint/utils.ts new file mode 100644 index 00000000000..e310b032075 --- /dev/null +++ b/apps/sim/tools/flint/utils.ts @@ -0,0 +1,30 @@ +import type { FlintBaseParams } from '@/tools/flint/types' +import type { ToolConfig } from '@/tools/types' + +/** + * Base URL for the Flint Agent Tasks API as documented at https://www.flint.com/docs/api. + */ +export const FLINT_API_BASE_URL = 'https://app.tryflint.com/api/v1' + +/** + * Builds the authentication headers required by every Flint endpoint. + * Flint authenticates with an API key sent as a bearer token. + */ +export function flintHeaders(params: FlintBaseParams): Record { + return { + Authorization: `Bearer ${params.apiKey.trim()}`, + 'Content-Type': 'application/json', + } +} + +/** + * Shared credential param definitions reused across all Flint tools. + */ +export const flintBaseParamFields = { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Flint API key (found in Flint team settings, starts with ak_)', + }, +} satisfies ToolConfig['params'] diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 12e788c5307..d50407ef521 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1024,6 +1024,7 @@ import { firefliesListUsersTool, firefliesUploadAudioTool, } from '@/tools/fireflies' +import { flintCreateTaskTool, flintGeneratePagesTool, flintGetTaskTool } from '@/tools/flint' import { functionExecuteTool } from '@/tools/function' import { gammaCheckStatusTool, @@ -4782,6 +4783,9 @@ export const tools: Record = { fireflies_create_bite: firefliesCreateBiteTool, fireflies_list_bites: firefliesListBitesTool, fireflies_list_contacts: firefliesListContactsTool, + flint_create_task: flintCreateTaskTool, + flint_generate_pages: flintGeneratePagesTool, + flint_get_task: flintGetTaskTool, gong_aggregate_activity: gongAggregateActivityTool, gong_aggregate_by_period: gongAggregateByPeriodTool, gong_answered_scorecards: gongAnsweredScorecardsTool, From ee0eead0f0d9506c0b5598dba4fce905b27f9b36 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Jul 2026 12:13:47 -0700 Subject: [PATCH 2/5] fix(flint): forward explicit publish=false, guard missing taskId, align default params branch with tool fallback --- apps/sim/blocks/blocks/flint.ts | 29 +++++++++++++++++--------- apps/sim/tools/flint/create_task.ts | 3 +++ apps/sim/tools/flint/generate_pages.ts | 3 +++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/sim/blocks/blocks/flint.ts b/apps/sim/blocks/blocks/flint.ts index 8495d0b4486..185ce601a69 100644 --- a/apps/sim/blocks/blocks/flint.ts +++ b/apps/sim/blocks/blocks/flint.ts @@ -2,6 +2,17 @@ import { FlintIcon } from '@/components/icons' import type { BlockConfig, BlockMeta } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' +/** + * Coerces the publish switch value to an explicit boolean, preserving an + * explicit false so Flint never falls back to its server-side default. + * Returns undefined only when the value was never set. + */ +function coercePublish(value: unknown): boolean | undefined { + if (value === true || value === 'true') return true + if (value === false || value === 'false') return false + return undefined +} + export const FlintBlock: BlockConfig = { type: 'flint', name: 'Flint', @@ -129,14 +140,6 @@ Return ONLY valid JSON - no explanations, no markdown code blocks.`, const base: Record = { apiKey: params.apiKey } switch (params.operation) { - case 'flint_create_task': - return { - ...base, - siteId: params.siteId, - prompt: params.prompt, - callbackUrl: params.callbackUrl || undefined, - publish: params.publish === true || params.publish === 'true' ? true : undefined, - } case 'flint_generate_pages': return { ...base, @@ -144,12 +147,18 @@ Return ONLY valid JSON - no explanations, no markdown code blocks.`, templatePageSlug: params.templatePageSlug, items: params.items, callbackUrl: params.callbackUrl || undefined, - publish: params.publish === true || params.publish === 'true' ? true : undefined, + publish: coercePublish(params.publish), } case 'flint_get_task': return { ...base, taskId: params.taskId } default: - return base + return { + ...base, + siteId: params.siteId, + prompt: params.prompt, + callbackUrl: params.callbackUrl || undefined, + publish: coercePublish(params.publish), + } } }, }, diff --git a/apps/sim/tools/flint/create_task.ts b/apps/sim/tools/flint/create_task.ts index 704a4db2d59..ee718ab4cb6 100644 --- a/apps/sim/tools/flint/create_task.ts +++ b/apps/sim/tools/flint/create_task.ts @@ -54,6 +54,9 @@ export const flintCreateTaskTool: ToolConfig { const data = await response.json() + if (!data?.taskId) { + throw new Error(data?.error || 'Flint did not return a task ID') + } return { success: true, output: { diff --git a/apps/sim/tools/flint/generate_pages.ts b/apps/sim/tools/flint/generate_pages.ts index 521c4b01557..123b382f98e 100644 --- a/apps/sim/tools/flint/generate_pages.ts +++ b/apps/sim/tools/flint/generate_pages.ts @@ -109,6 +109,9 @@ export const flintGeneratePagesTool: ToolConfig< transformResponse: async (response) => { const data = await response.json() + if (!data?.taskId) { + throw new Error(data?.error || 'Flint did not return a task ID') + } return { success: true, output: { From d9921b74e4e239dc7df026f5d1a69497d6b46a97 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Jul 2026 12:15:33 -0700 Subject: [PATCH 3/5] docs(flint): add manual intro section to integration docs page --- .../content/docs/en/integrations/flint.mdx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/docs/content/docs/en/integrations/flint.mdx b/apps/docs/content/docs/en/integrations/flint.mdx index 25eb095995e..1a9c44877d2 100644 --- a/apps/docs/content/docs/en/integrations/flint.mdx +++ b/apps/docs/content/docs/en/integrations/flint.mdx @@ -10,6 +10,29 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" color="#F6F54F" /> +{/* MANUAL-CONTENT-START:intro */} +[Flint](https://www.flint.com/) is an AI website platform where background agents build and update your site for you. Through the Agent Tasks API, you can programmatically kick off site changes from a natural-language prompt, generate batches of pages from a template, and monitor each task until it completes. + +**Why Flint?** +- **Agent-Driven Site Changes:** Describe the change in plain language — "Add a new About page with a team section" — and a background agent makes it happen. +- **Programmatic Page Generation:** Generate up to 10 pages per task from an existing template page, each with its own slug and content context — ideal for case studies, location pages, and programmatic SEO. +- **Controlled Publishing:** Every task can either publish automatically on completion or leave changes unpublished for review. +- **Full Task Visibility:** Poll any task for its status and get back the created, modified, and deleted pages with preview, edit, and published URLs. + +**Using Flint in Sim** + +Sim's Flint integration connects your workflows directly to the Flint Agent Tasks API using an API key from your Flint team settings. Three operations cover the full task lifecycle: Create Task starts a prompt-driven site change, Generate Pages fans a template out into a batch of new pages, and Get Task reports status and results. + +**Key benefits of using Flint in Sim:** +- **Content pipelines:** Read rows from a table or spreadsheet and generate a landing page per row from a Flint template. +- **Event-driven site updates:** Trigger site changes from Slack requests, closed-won deals, or new GitHub releases. +- **Safe review workflows:** Leave publishing off, collect preview URLs from Get Task, and publish only after approval. +- **Reliable monitoring:** Poll task status on a schedule, write published URLs back to your data, and alert on failed tasks with their error messages. + +Whether you're scaling programmatic SEO, keeping marketing pages in sync with your business systems, or automating site maintenance, Flint in Sim turns your website into something your workflows can edit. Configure your API key, pick an operation, and let the agent do the work. +{/* MANUAL-CONTENT-END */} + + ## Usage Instructions Create background agent tasks that modify your Flint sites from natural-language prompts, generate batches of pages from a template, and check task status and results. From 511c1c004e22487329a922b0497349b64da7fe18 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Jul 2026 12:20:36 -0700 Subject: [PATCH 4/5] fix(flint): fail get_task on OK responses without a task ID --- apps/sim/tools/flint/get_task.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/sim/tools/flint/get_task.ts b/apps/sim/tools/flint/get_task.ts index 8778e1be899..ed424ac66fc 100644 --- a/apps/sim/tools/flint/get_task.ts +++ b/apps/sim/tools/flint/get_task.ts @@ -54,6 +54,9 @@ export const flintGetTaskTool: ToolConfig { const data = await response.json() + if (!data?.taskId) { + throw new Error(data?.error || 'Flint did not return a task ID') + } return { success: true, output: { From 4458216796d2de23ca89059f584ac4dd1fb6216f Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 13 Jul 2026 12:31:51 -0700 Subject: [PATCH 5/5] fix(flint): drop json-object generation type so the wand emits the pages array --- apps/sim/blocks/blocks/flint.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/sim/blocks/blocks/flint.ts b/apps/sim/blocks/blocks/flint.ts index 185ce601a69..eb615730a4b 100644 --- a/apps/sim/blocks/blocks/flint.ts +++ b/apps/sim/blocks/blocks/flint.ts @@ -96,9 +96,8 @@ Each page object must have exactly these fields: - "context": Content details the agent should use to fill in the template The array must contain between 1 and 10 items. -Return ONLY valid JSON - no explanations, no markdown code blocks.`, +Return ONLY the raw JSON array starting with [ and ending with ] - no explanations, no markdown code blocks.`, placeholder: 'Describe the pages you want to generate...', - generationType: 'json-object', }, }, {