From e62677005267a1c3ec4beb580506628f3d5b2d31 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 26 Feb 2026 17:06:27 -0800 Subject: [PATCH 1/5] feat(gamma): add gamma integration for AI-powered content generation --- apps/docs/components/icons.tsx | 27 ++ apps/docs/components/ui/icon-mapping.ts | 2 + apps/docs/content/docs/en/tools/gamma.mdx | 166 +++++++++ apps/docs/content/docs/en/tools/meta.json | 1 + apps/sim/blocks/blocks/gamma.ts | 340 ++++++++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 27 ++ apps/sim/tools/gamma/check_status.ts | 104 ++++++ apps/sim/tools/gamma/generate.ts | 189 ++++++++++ .../sim/tools/gamma/generate_from_template.ts | 121 +++++++ apps/sim/tools/gamma/index.ts | 11 + apps/sim/tools/gamma/list_folders.ts | 91 +++++ apps/sim/tools/gamma/list_themes.ts | 113 ++++++ apps/sim/tools/gamma/types.ts | 173 +++++++++ apps/sim/tools/registry.ts | 12 + 15 files changed, 1379 insertions(+) create mode 100644 apps/docs/content/docs/en/tools/gamma.mdx create mode 100644 apps/sim/blocks/blocks/gamma.ts create mode 100644 apps/sim/tools/gamma/check_status.ts create mode 100644 apps/sim/tools/gamma/generate.ts create mode 100644 apps/sim/tools/gamma/generate_from_template.ts create mode 100644 apps/sim/tools/gamma/index.ts create mode 100644 apps/sim/tools/gamma/list_folders.ts create mode 100644 apps/sim/tools/gamma/list_themes.ts create mode 100644 apps/sim/tools/gamma/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 9da5a57508..6531501ee4 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -526,6 +526,33 @@ export function SlackMonoIcon(props: SVGProps) { ) } +export function GammaIcon(props: SVGProps) { + return ( + + + + + + + + ) +} + export function GithubIcon(props: SVGProps) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index a1af3619d0..37447dedf1 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -40,6 +40,7 @@ import { EyeIcon, FirecrawlIcon, FirefliesIcon, + GammaIcon, GithubIcon, GitLabIcon, GmailIcon, @@ -190,6 +191,7 @@ export const blockTypeToIconMap: Record = { file_v3: DocumentIcon, firecrawl: FirecrawlIcon, fireflies_v2: FirefliesIcon, + gamma: GammaIcon, github_v2: GithubIcon, gitlab: GitLabIcon, gmail_v2: GmailIcon, diff --git a/apps/docs/content/docs/en/tools/gamma.mdx b/apps/docs/content/docs/en/tools/gamma.mdx new file mode 100644 index 0000000000..c05d187cf4 --- /dev/null +++ b/apps/docs/content/docs/en/tools/gamma.mdx @@ -0,0 +1,166 @@ +--- +title: Gamma +description: Generate presentations, documents, and webpages with AI +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Gamma](https://gamma.app/) is an AI-powered platform for creating presentations, documents, webpages, and social posts. Gamma's API lets you programmatically generate polished, visually rich content from text prompts, adapt existing templates, and manage workspace assets like themes and folders. + +With Gamma, you can: + +- **Generate presentations and documents:** Create slide decks, documents, webpages, and social posts from text input with full control over format, tone, and image sourcing. +- **Create from templates:** Adapt existing Gamma templates with custom prompts to quickly produce tailored content. +- **Check generation status:** Poll for completion of async generation jobs and retrieve the final Gamma URL. +- **Browse themes and folders:** List available workspace themes and folders to organize and style your generated content. + +In Sim, the Gamma integration enables your agents to automatically generate presentations and documents, create content from templates, and manage workspace assets directly within your workflows. This allows you to automate content creation pipelines, batch-produce slide decks, and integrate AI-generated presentations into broader business automation scenarios. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Gamma into the workflow. Can generate presentations, documents, webpages, and social posts from text, create from templates, check generation status, and browse themes and folders. + + + +## Tools + +### `gamma_generate` + +Generate a new Gamma presentation, document, webpage, or social post from text input. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Gamma API key | +| `inputText` | string | Yes | Text and image URLs used to generate your gamma \(1-100,000 tokens\) | +| `textMode` | string | Yes | How to handle input text: generate \(AI expands\), condense \(AI summarizes\), or preserve \(keep as-is\) | +| `format` | string | No | Output format: presentation, document, webpage, or social \(default: presentation\) | +| `themeId` | string | No | Custom Gamma workspace theme ID \(use List Themes to find available themes\) | +| `numCards` | number | No | Number of cards/slides to generate \(1-60 for Pro, 1-75 for Ultra; default: 10\) | +| `cardSplit` | string | No | How to split content into cards: auto or inputTextBreaks \(default: auto\) | +| `cardDimensions` | string | No | Card aspect ratio. Presentation: fluid, 16x9, 4x3. Document: fluid, pageless, letter, a4. Social: 1x1, 4x5, 9x16 | +| `additionalInstructions` | string | No | Additional instructions for the AI generation \(max 2000 chars\) | +| `exportAs` | string | No | Automatically export the generated gamma as pdf or pptx | +| `folderIds` | string | No | Comma-separated folder IDs to store the generated gamma in | +| `textAmount` | string | No | Amount of text per card: brief, medium, detailed, or extensive | +| `textTone` | string | No | Tone of the generated text, e.g. "professional", "casual" \(max 500 chars\) | +| `textAudience` | string | No | Target audience for the generated text, e.g. "executives", "students" \(max 500 chars\) | +| `textLanguage` | string | No | Language code for the generated text \(default: en\) | +| `imageSource` | string | No | Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages | +| `imageModel` | string | No | AI image generation model to use when imageSource is aiGenerated | +| `imageStyle` | string | No | Style directive for AI-generated images, e.g. "watercolor", "photorealistic" \(max 500 chars\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `generationId` | string | The ID of the generation job. Use with Check Status to poll for completion. | + +### `gamma_generate_from_template` + +Generate a new Gamma by adapting an existing template with a prompt. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Gamma API key | +| `gammaId` | string | Yes | The ID of the template gamma to adapt | +| `prompt` | string | Yes | Instructions for how to adapt the template \(1-100,000 tokens\) | +| `themeId` | string | No | Custom Gamma workspace theme ID to apply | +| `exportAs` | string | No | Automatically export the generated gamma as pdf or pptx | +| `folderIds` | string | No | Comma-separated folder IDs to store the generated gamma in | +| `imageSource` | string | No | Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages | +| `imageModel` | string | No | AI image generation model to use when imageSource is aiGenerated | +| `imageStyle` | string | No | Style directive for AI-generated images, e.g. "watercolor", "photorealistic" \(max 500 chars\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `generationId` | string | The ID of the generation job. Use with Check Status to poll for completion. | + +### `gamma_check_status` + +Check the status of a Gamma generation job. Returns the gamma URL when completed, or error details if failed. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Gamma API key | +| `generationId` | string | Yes | The generation ID returned by the Generate or Generate from Template tool | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `generationId` | string | The generation ID that was checked | +| `status` | string | Generation status: pending, completed, or failed | +| `gammaUrl` | string | URL of the generated gamma \(only present when status is completed\) | +| `credits` | object | Credit usage information \(only present when status is completed\) | +| ↳ `deducted` | number | Number of credits deducted for this generation | +| ↳ `remaining` | number | Remaining credits in the account | +| `error` | object | Error details \(only present when status is failed\) | +| ↳ `message` | string | Human-readable error message | +| ↳ `statusCode` | number | HTTP status code of the error | + +### `gamma_list_themes` + +List available themes in your Gamma workspace. Returns theme IDs, names, and keywords for styling. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Gamma API key | +| `query` | string | No | Search query to filter themes by name \(case-insensitive\) | +| `limit` | number | No | Maximum number of themes to return per page \(max 50\) | +| `after` | string | No | Pagination cursor from a previous response \(nextCursor\) to fetch the next page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `themes` | array | List of available themes | +| ↳ `id` | string | Theme ID \(use with themeId parameter\) | +| ↳ `name` | string | Theme display name | +| ↳ `type` | string | Theme type: standard or custom | +| ↳ `colorKeywords` | array | Color descriptors for this theme | +| ↳ `toneKeywords` | array | Tone descriptors for this theme | +| `hasMore` | boolean | Whether more results are available on the next page | +| `nextCursor` | string | Pagination cursor to pass as the after parameter for the next page | + +### `gamma_list_folders` + +List available folders in your Gamma workspace. Returns folder IDs and names for organizing generated content. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Gamma API key | +| `query` | string | No | Search query to filter folders by name \(case-sensitive\) | +| `limit` | number | No | Maximum number of folders to return per page \(max 50\) | +| `after` | string | No | Pagination cursor from a previous response \(nextCursor\) to fetch the next page | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `folders` | array | List of available folders | +| ↳ `id` | string | Folder ID \(use with folderIds parameter\) | +| ↳ `name` | string | Folder display name | +| `hasMore` | boolean | Whether more results are available on the next page | +| `nextCursor` | string | Pagination cursor to pass as the after parameter for the next page | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index ec0851ee59..fcb1dd02ce 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -35,6 +35,7 @@ "file", "firecrawl", "fireflies", + "gamma", "github", "gitlab", "gmail", diff --git a/apps/sim/blocks/blocks/gamma.ts b/apps/sim/blocks/blocks/gamma.ts new file mode 100644 index 0000000000..2e66748188 --- /dev/null +++ b/apps/sim/blocks/blocks/gamma.ts @@ -0,0 +1,340 @@ +import { GammaIcon } from '@/components/icons' +import { AuthMode, type BlockConfig } from '@/blocks/types' +import type { GammaResponse } from '@/tools/gamma/types' + +export const GammaBlock: BlockConfig = { + type: 'gamma', + name: 'Gamma', + description: 'Generate presentations, documents, and webpages with AI', + longDescription: + 'Integrate Gamma into the workflow. Can generate presentations, documents, webpages, and social posts from text, create from templates, check generation status, and browse themes and folders.', + docsLink: 'https://docs.sim.ai/tools/gamma', + category: 'tools', + bgColor: '#002253', + icon: GammaIcon, + authMode: AuthMode.ApiKey, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Generate', id: 'generate' }, + { label: 'Generate from Template', id: 'generate_from_template' }, + { label: 'Check Status', id: 'check_status' }, + { label: 'List Themes', id: 'list_themes' }, + { label: 'List Folders', id: 'list_folders' }, + ], + value: () => 'generate', + }, + // Generate operation inputs + { + id: 'inputText', + title: 'Input Text', + type: 'long-input', + required: { field: 'operation', value: 'generate' }, + placeholder: 'Enter text content to generate from...', + condition: { field: 'operation', value: 'generate' }, + }, + { + id: 'textMode', + title: 'Text Mode', + type: 'dropdown', + options: [ + { label: 'Generate', id: 'generate' }, + { label: 'Condense', id: 'condense' }, + { label: 'Preserve', id: 'preserve' }, + ], + value: () => 'generate', + condition: { field: 'operation', value: 'generate' }, + }, + { + id: 'format', + title: 'Format', + type: 'dropdown', + options: [ + { label: 'Presentation', id: 'presentation' }, + { label: 'Document', id: 'document' }, + { label: 'Webpage', id: 'webpage' }, + { label: 'Social', id: 'social' }, + ], + value: () => 'presentation', + condition: { field: 'operation', value: 'generate' }, + }, + { + id: 'numCards', + title: 'Number of Cards', + type: 'short-input', + placeholder: '10', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'additionalInstructions', + title: 'Additional Instructions', + type: 'long-input', + placeholder: 'Any additional instructions for the generation...', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'textAmount', + title: 'Text Amount', + type: 'dropdown', + options: [ + { label: 'Brief', id: 'brief' }, + { label: 'Medium', id: 'medium' }, + { label: 'Detailed', id: 'detailed' }, + { label: 'Extensive', id: 'extensive' }, + ], + value: () => 'medium', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'textTone', + title: 'Tone', + type: 'short-input', + placeholder: 'e.g., professional, casual, academic', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'textAudience', + title: 'Audience', + type: 'short-input', + placeholder: 'e.g., executives, students, developers', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'textLanguage', + title: 'Language', + type: 'short-input', + placeholder: 'en', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'cardSplit', + title: 'Card Split', + type: 'dropdown', + options: [ + { label: 'Auto', id: 'auto' }, + { label: 'Input Text Breaks', id: 'inputTextBreaks' }, + ], + value: () => 'auto', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + }, + { + id: 'cardDimensions', + title: 'Card Dimensions', + type: 'short-input', + placeholder: 'e.g., 16x9, fluid, letter, a4', + condition: { field: 'operation', value: 'generate' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate the correct card dimensions value for a Gamma generation. +Valid values depend on the format: +- Presentation: "fluid", "16x9", "4x3" +- Document: "fluid", "pageless", "letter", "a4" +- Social: "1x1", "4x5", "9x16" +Return ONLY the dimension value string, nothing else.`, + placeholder: 'Describe the desired dimensions (e.g., "widescreen slides")...', + }, + }, + { + id: 'imageSource', + title: 'Image Source', + type: 'dropdown', + options: [ + { label: 'AI Generated', id: 'aiGenerated' }, + { label: 'Pictographic', id: 'pictographic' }, + { label: 'Unsplash', id: 'unsplash' }, + { label: 'Web (All Images)', id: 'webAllImages' }, + { label: 'Web (Free to Use)', id: 'webFreeToUse' }, + { label: 'Web (Free Commercial)', id: 'webFreeToUseCommercially' }, + { label: 'Giphy', id: 'giphy' }, + { label: 'Placeholder', id: 'placeholder' }, + { label: 'No Images', id: 'noImages' }, + ], + value: () => 'aiGenerated', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + }, + { + id: 'imageModel', + title: 'Image Model', + type: 'short-input', + placeholder: 'AI image model (when using AI Generated source)', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + }, + { + id: 'imageStyle', + title: 'Image Style', + type: 'short-input', + placeholder: 'e.g., watercolor, photorealistic, minimalist', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + }, + { + id: 'exportAs', + title: 'Export As', + type: 'dropdown', + options: [ + { label: 'None', id: '' }, + { label: 'PDF', id: 'pdf' }, + { label: 'PPTX', id: 'pptx' }, + ], + value: () => '', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + }, + { + id: 'themeId', + title: 'Theme ID', + type: 'short-input', + placeholder: 'Enter theme ID (use List Themes to find)', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + }, + { + id: 'folderIds', + title: 'Folder IDs', + type: 'short-input', + placeholder: 'Comma-separated folder IDs', + condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: `Generate a comma-separated list of Gamma folder IDs. +The user will describe which folders to store the generated gamma in. +Each folder ID is a string identifier from the Gamma workspace. +Use the List Folders operation to find available folder IDs first. +Return ONLY the comma-separated IDs, nothing else. +Example: "folder_abc123, folder_def456"`, + placeholder: 'Describe which folders to store the gamma in...', + }, + }, + // Generate from Template inputs + { + id: 'gammaId', + title: 'Template Gamma ID', + type: 'short-input', + required: { field: 'operation', value: 'generate_from_template' }, + placeholder: 'Enter the template gamma ID', + condition: { field: 'operation', value: 'generate_from_template' }, + }, + { + id: 'prompt', + title: 'Prompt', + type: 'long-input', + required: { field: 'operation', value: 'generate_from_template' }, + placeholder: 'Instructions for adapting the template...', + condition: { field: 'operation', value: 'generate_from_template' }, + }, + // Check Status inputs + { + id: 'generationId', + title: 'Generation ID', + type: 'short-input', + required: { field: 'operation', value: 'check_status' }, + placeholder: 'Enter the generation ID to check', + condition: { field: 'operation', value: 'check_status' }, + }, + // List Themes / List Folders inputs + { + id: 'query', + title: 'Search Query', + type: 'short-input', + placeholder: 'Filter by name...', + condition: { field: 'operation', value: ['list_themes', 'list_folders'] }, + mode: 'advanced', + }, + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: '50', + condition: { field: 'operation', value: ['list_themes', 'list_folders'] }, + mode: 'advanced', + }, + { + id: 'after', + title: 'Pagination Cursor', + type: 'short-input', + placeholder: 'nextCursor from previous response', + condition: { field: 'operation', value: ['list_themes', 'list_folders'] }, + mode: 'advanced', + }, + // API Key (common) + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + required: true, + placeholder: 'Enter your Gamma API key', + password: true, + }, + ], + tools: { + access: [ + 'gamma_generate', + 'gamma_generate_from_template', + 'gamma_check_status', + 'gamma_list_themes', + 'gamma_list_folders', + ], + config: { + tool: (params) => `gamma_${params.operation}`, + params: (params) => { + const result: Record = {} + if (params.numCards) result.numCards = Number(params.numCards) + if (params.limit) result.limit = Number(params.limit) + if (params.exportAs === '') result.exportAs = undefined + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Gamma API key' }, + inputText: { type: 'string', description: 'Text content for generation' }, + textMode: { type: 'string', description: 'Text handling mode' }, + format: { type: 'string', description: 'Output format' }, + numCards: { type: 'number', description: 'Number of cards to generate' }, + additionalInstructions: { type: 'string', description: 'Additional generation instructions' }, + textAmount: { type: 'string', description: 'Amount of text to generate' }, + textTone: { type: 'string', description: 'Tone of generated text' }, + textAudience: { type: 'string', description: 'Target audience' }, + textLanguage: { type: 'string', description: 'Language code' }, + cardSplit: { type: 'string', description: 'Card splitting strategy' }, + cardDimensions: { type: 'string', description: 'Card aspect ratio' }, + imageSource: { type: 'string', description: 'Image source for generation' }, + imageModel: { type: 'string', description: 'AI image model' }, + imageStyle: { type: 'string', description: 'Image style directive' }, + exportAs: { type: 'string', description: 'Export format' }, + themeId: { type: 'string', description: 'Theme ID' }, + folderIds: { type: 'string', description: 'Comma-separated folder IDs' }, + gammaId: { type: 'string', description: 'Template gamma ID' }, + prompt: { type: 'string', description: 'Template adaptation prompt' }, + generationId: { type: 'string', description: 'Generation ID to check' }, + query: { type: 'string', description: 'Search query' }, + limit: { type: 'number', description: 'Result limit' }, + after: { type: 'string', description: 'Pagination cursor' }, + }, + outputs: { + generationId: { type: 'string', description: 'Generation job ID' }, + status: { type: 'string', description: 'Generation status' }, + gammaUrl: { type: 'string', description: 'URL of the generated gamma' }, + credits: { type: 'json', description: 'Credit usage (deducted, remaining)' }, + error: { type: 'json', description: 'Error details if generation failed' }, + themes: { type: 'json', description: 'List of themes' }, + folders: { type: 'json', description: 'List of folders' }, + hasMore: { type: 'boolean', description: 'Whether more results are available' }, + nextCursor: { type: 'string', description: 'Pagination cursor for next page' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index c203af4f66..88d6fc59a7 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -39,6 +39,7 @@ import { FileBlock, FileV2Block, FileV3Block } from '@/blocks/blocks/file' import { FirecrawlBlock } from '@/blocks/blocks/firecrawl' import { FirefliesBlock, FirefliesV2Block } from '@/blocks/blocks/fireflies' import { FunctionBlock } from '@/blocks/blocks/function' +import { GammaBlock } from '@/blocks/blocks/gamma' import { GenericWebhookBlock } from '@/blocks/blocks/generic_webhook' import { GitHubBlock, GitHubV2Block } from '@/blocks/blocks/github' import { GitLabBlock } from '@/blocks/blocks/gitlab' @@ -227,6 +228,7 @@ export const registry: Record = { fireflies: FirefliesBlock, fireflies_v2: FirefliesV2Block, function: FunctionBlock, + gamma: GammaBlock, generic_webhook: GenericWebhookBlock, github: GitHubBlock, github_v2: GitHubV2Block, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 9da5a57508..6531501ee4 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -526,6 +526,33 @@ export function SlackMonoIcon(props: SVGProps) { ) } +export function GammaIcon(props: SVGProps) { + return ( + + + + + + + + ) +} + export function GithubIcon(props: SVGProps) { return ( diff --git a/apps/sim/tools/gamma/check_status.ts b/apps/sim/tools/gamma/check_status.ts new file mode 100644 index 0000000000..ba005038bc --- /dev/null +++ b/apps/sim/tools/gamma/check_status.ts @@ -0,0 +1,104 @@ +import type { GammaCheckStatusParams, GammaCheckStatusResponse } from '@/tools/gamma/types' +import type { ToolConfig } from '@/tools/types' + +export const checkStatusTool: ToolConfig = { + id: 'gamma_check_status', + name: 'Gamma Check Status', + description: + 'Check the status of a Gamma generation job. Returns the gamma URL when completed, or error details if failed.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gamma API key', + }, + generationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The generation ID returned by the Generate or Generate from Template tool', + }, + }, + + request: { + url: (params) => `https://public-api.gamma.app/v1.0/generations/${params.generationId}`, + method: 'GET', + headers: (params) => ({ + 'X-API-KEY': params.apiKey, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + generationId: data.generationId ?? '', + status: data.status ?? 'pending', + gammaUrl: data.gammaUrl ?? null, + credits: { + deducted: data.credits?.deducted ?? null, + remaining: data.credits?.remaining ?? null, + }, + error: { + message: data.error?.message ?? null, + statusCode: data.error?.statusCode ?? null, + }, + }, + } + }, + + outputs: { + generationId: { + type: 'string', + description: 'The generation ID that was checked', + }, + status: { + type: 'string', + description: 'Generation status: pending, completed, or failed', + }, + gammaUrl: { + type: 'string', + description: 'URL of the generated gamma (only present when status is completed)', + optional: true, + }, + credits: { + type: 'object', + description: 'Credit usage information (only present when status is completed)', + optional: true, + properties: { + deducted: { + type: 'number', + description: 'Number of credits deducted for this generation', + optional: true, + }, + remaining: { + type: 'number', + description: 'Remaining credits in the account', + optional: true, + }, + }, + }, + error: { + type: 'object', + description: 'Error details (only present when status is failed)', + optional: true, + properties: { + message: { + type: 'string', + description: 'Human-readable error message', + optional: true, + }, + statusCode: { + type: 'number', + description: 'HTTP status code of the error', + optional: true, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/gamma/generate.ts b/apps/sim/tools/gamma/generate.ts new file mode 100644 index 0000000000..5f30f0b684 --- /dev/null +++ b/apps/sim/tools/gamma/generate.ts @@ -0,0 +1,189 @@ +import type { GammaGenerateParams, GammaGenerateResponse } from '@/tools/gamma/types' +import type { ToolConfig } from '@/tools/types' + +export const generateTool: ToolConfig = { + id: 'gamma_generate', + name: 'Gamma Generate', + description: + 'Generate a new Gamma presentation, document, webpage, or social post from text input.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gamma API key', + }, + inputText: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Text and image URLs used to generate your gamma (1-100,000 tokens)', + }, + textMode: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'How to handle input text: generate (AI expands), condense (AI summarizes), or preserve (keep as-is)', + }, + format: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Output format: presentation, document, webpage, or social (default: presentation)', + }, + themeId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Custom Gamma workspace theme ID (use List Themes to find available themes)', + }, + numCards: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of cards/slides to generate (1-60 for Pro, 1-75 for Ultra; default: 10)', + }, + cardSplit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'How to split content into cards: auto or inputTextBreaks (default: auto)', + }, + cardDimensions: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Card aspect ratio. Presentation: fluid, 16x9, 4x3. Document: fluid, pageless, letter, a4. Social: 1x1, 4x5, 9x16', + }, + additionalInstructions: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Additional instructions for the AI generation (max 2000 chars)', + }, + exportAs: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Automatically export the generated gamma as pdf or pptx', + }, + folderIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated folder IDs to store the generated gamma in', + }, + textAmount: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Amount of text per card: brief, medium, detailed, or extensive', + }, + textTone: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Tone of the generated text, e.g. "professional", "casual" (max 500 chars)', + }, + textAudience: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Target audience for the generated text, e.g. "executives", "students" (max 500 chars)', + }, + textLanguage: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Language code for the generated text (default: en)', + }, + imageSource: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages', + }, + imageModel: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'AI image generation model to use when imageSource is aiGenerated', + }, + imageStyle: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Style directive for AI-generated images, e.g. "watercolor", "photorealistic" (max 500 chars)', + }, + }, + + request: { + url: 'https://public-api.gamma.app/v1.0/generations', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + 'X-API-KEY': params.apiKey, + }), + body: (params) => { + const body: Record = { + inputText: params.inputText, + textMode: params.textMode, + } + + if (params.format) body.format = params.format + if (params.themeId) body.themeId = params.themeId + if (params.numCards) body.numCards = params.numCards + if (params.cardSplit) body.cardSplit = params.cardSplit + if (params.additionalInstructions) body.additionalInstructions = params.additionalInstructions + if (params.exportAs) body.exportAs = params.exportAs + if (params.folderIds) { + body.folderIds = params.folderIds.split(',').map((id: string) => id.trim()) + } + + const textOptions: Record = {} + if (params.textAmount) textOptions.amount = params.textAmount + if (params.textTone) textOptions.tone = params.textTone + if (params.textAudience) textOptions.audience = params.textAudience + if (params.textLanguage) textOptions.language = params.textLanguage + if (Object.keys(textOptions).length > 0) body.textOptions = textOptions + + const imageOptions: Record = {} + if (params.imageSource) imageOptions.source = params.imageSource + if (params.imageModel) imageOptions.model = params.imageModel + if (params.imageStyle) imageOptions.style = params.imageStyle + if (Object.keys(imageOptions).length > 0) body.imageOptions = imageOptions + + const cardOptions: Record = {} + if (params.cardDimensions) cardOptions.dimensions = params.cardDimensions + if (Object.keys(cardOptions).length > 0) body.cardOptions = cardOptions + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + generationId: data.generationId ?? '', + }, + } + }, + + outputs: { + generationId: { + type: 'string', + description: 'The ID of the generation job. Use with Check Status to poll for completion.', + }, + }, +} diff --git a/apps/sim/tools/gamma/generate_from_template.ts b/apps/sim/tools/gamma/generate_from_template.ts new file mode 100644 index 0000000000..1d62cb31d5 --- /dev/null +++ b/apps/sim/tools/gamma/generate_from_template.ts @@ -0,0 +1,121 @@ +import type { + GammaGenerateFromTemplateParams, + GammaGenerateFromTemplateResponse, +} from '@/tools/gamma/types' +import type { ToolConfig } from '@/tools/types' + +export const generateFromTemplateTool: ToolConfig< + GammaGenerateFromTemplateParams, + GammaGenerateFromTemplateResponse +> = { + id: 'gamma_generate_from_template', + name: 'Gamma Generate from Template', + description: 'Generate a new Gamma by adapting an existing template with a prompt.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gamma API key', + }, + gammaId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ID of the template gamma to adapt', + }, + prompt: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Instructions for how to adapt the template (1-100,000 tokens)', + }, + themeId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Custom Gamma workspace theme ID to apply', + }, + exportAs: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Automatically export the generated gamma as pdf or pptx', + }, + folderIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated folder IDs to store the generated gamma in', + }, + imageSource: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages', + }, + imageModel: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'AI image generation model to use when imageSource is aiGenerated', + }, + imageStyle: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Style directive for AI-generated images, e.g. "watercolor", "photorealistic" (max 500 chars)', + }, + }, + + request: { + url: 'https://public-api.gamma.app/v1.0/generations/from-template', + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + 'X-API-KEY': params.apiKey, + }), + body: (params) => { + const body: Record = { + gammaId: params.gammaId, + prompt: params.prompt, + } + + if (params.themeId) body.themeId = params.themeId + if (params.exportAs) body.exportAs = params.exportAs + if (params.folderIds) { + body.folderIds = params.folderIds.split(',').map((id: string) => id.trim()) + } + + const imageOptions: Record = {} + if (params.imageSource) imageOptions.source = params.imageSource + if (params.imageModel) imageOptions.model = params.imageModel + if (params.imageStyle) imageOptions.style = params.imageStyle + if (Object.keys(imageOptions).length > 0) body.imageOptions = imageOptions + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + generationId: data.generationId ?? '', + }, + } + }, + + outputs: { + generationId: { + type: 'string', + description: 'The ID of the generation job. Use with Check Status to poll for completion.', + }, + }, +} diff --git a/apps/sim/tools/gamma/index.ts b/apps/sim/tools/gamma/index.ts new file mode 100644 index 0000000000..792a5260da --- /dev/null +++ b/apps/sim/tools/gamma/index.ts @@ -0,0 +1,11 @@ +import { checkStatusTool } from '@/tools/gamma/check_status' +import { generateTool } from '@/tools/gamma/generate' +import { generateFromTemplateTool } from '@/tools/gamma/generate_from_template' +import { listFoldersTool } from '@/tools/gamma/list_folders' +import { listThemesTool } from '@/tools/gamma/list_themes' + +export const gammaGenerateTool = generateTool +export const gammaGenerateFromTemplateTool = generateFromTemplateTool +export const gammaCheckStatusTool = checkStatusTool +export const gammaListThemesTool = listThemesTool +export const gammaListFoldersTool = listFoldersTool diff --git a/apps/sim/tools/gamma/list_folders.ts b/apps/sim/tools/gamma/list_folders.ts new file mode 100644 index 0000000000..1a5be9afad --- /dev/null +++ b/apps/sim/tools/gamma/list_folders.ts @@ -0,0 +1,91 @@ +import type { GammaListFoldersParams, GammaListFoldersResponse } from '@/tools/gamma/types' +import type { ToolConfig } from '@/tools/types' + +export const listFoldersTool: ToolConfig = { + id: 'gamma_list_folders', + name: 'Gamma List Folders', + description: + 'List available folders in your Gamma workspace. Returns folder IDs and names for organizing generated content.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gamma API key', + }, + query: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Search query to filter folders by name (case-sensitive)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of folders to return per page (max 50)', + }, + after: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response (nextCursor) to fetch the next page', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://public-api.gamma.app/v1.0/folders') + if (params.query) url.searchParams.append('query', params.query) + if (params.limit) url.searchParams.append('limit', String(params.limit)) + if (params.after) url.searchParams.append('after', params.after) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'X-API-KEY': params.apiKey, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const items = Array.isArray(data.data) ? data.data : Array.isArray(data) ? data : [] + + return { + success: true, + output: { + folders: items.map((folder: { id?: string; name?: string }) => ({ + id: folder.id ?? '', + name: folder.name ?? '', + })), + hasMore: data.hasMore ?? false, + nextCursor: data.nextCursor ?? null, + }, + } + }, + + outputs: { + folders: { + type: 'array', + description: 'List of available folders', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Folder ID (use with folderIds parameter)' }, + name: { type: 'string', description: 'Folder display name' }, + }, + }, + }, + hasMore: { + type: 'boolean', + description: 'Whether more results are available on the next page', + }, + nextCursor: { + type: 'string', + description: 'Pagination cursor to pass as the after parameter for the next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/gamma/list_themes.ts b/apps/sim/tools/gamma/list_themes.ts new file mode 100644 index 0000000000..1ffc17f26f --- /dev/null +++ b/apps/sim/tools/gamma/list_themes.ts @@ -0,0 +1,113 @@ +import type { GammaListThemesParams, GammaListThemesResponse } from '@/tools/gamma/types' +import type { ToolConfig } from '@/tools/types' + +export const listThemesTool: ToolConfig = { + id: 'gamma_list_themes', + name: 'Gamma List Themes', + description: + 'List available themes in your Gamma workspace. Returns theme IDs, names, and keywords for styling.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Gamma API key', + }, + query: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Search query to filter themes by name (case-insensitive)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of themes to return per page (max 50)', + }, + after: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response (nextCursor) to fetch the next page', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://public-api.gamma.app/v1.0/themes') + if (params.query) url.searchParams.append('query', params.query) + if (params.limit) url.searchParams.append('limit', String(params.limit)) + if (params.after) url.searchParams.append('after', params.after) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + 'X-API-KEY': params.apiKey, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const items = Array.isArray(data.data) ? data.data : Array.isArray(data) ? data : [] + + return { + success: true, + output: { + themes: items.map( + (theme: { + id?: string + name?: string + type?: string + colorKeywords?: string[] + toneKeywords?: string[] + }) => ({ + id: theme.id ?? '', + name: theme.name ?? '', + type: theme.type ?? '', + colorKeywords: theme.colorKeywords ?? [], + toneKeywords: theme.toneKeywords ?? [], + }) + ), + hasMore: data.hasMore ?? false, + nextCursor: data.nextCursor ?? null, + }, + } + }, + + outputs: { + themes: { + type: 'array', + description: 'List of available themes', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Theme ID (use with themeId parameter)' }, + name: { type: 'string', description: 'Theme display name' }, + type: { type: 'string', description: 'Theme type: standard or custom' }, + colorKeywords: { + type: 'array', + description: 'Color descriptors for this theme', + items: { type: 'string', description: 'Color keyword' }, + }, + toneKeywords: { + type: 'array', + description: 'Tone descriptors for this theme', + items: { type: 'string', description: 'Tone keyword' }, + }, + }, + }, + }, + hasMore: { + type: 'boolean', + description: 'Whether more results are available on the next page', + }, + nextCursor: { + type: 'string', + description: 'Pagination cursor to pass as the after parameter for the next page', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/gamma/types.ts b/apps/sim/tools/gamma/types.ts new file mode 100644 index 0000000000..e96114b4a0 --- /dev/null +++ b/apps/sim/tools/gamma/types.ts @@ -0,0 +1,173 @@ +import type { ToolResponse } from '@/tools/types' + +/** + * Base parameters shared across all Gamma API tools. + */ +export interface GammaBaseParams { + apiKey: string +} + +/** + * Parameters for the Generate a Gamma tool. + */ +export interface GammaGenerateParams extends GammaBaseParams { + inputText: string + textMode: 'generate' | 'condense' | 'preserve' + format?: 'presentation' | 'document' | 'webpage' | 'social' + themeId?: string + numCards?: number + cardSplit?: 'auto' | 'inputTextBreaks' + cardDimensions?: string + additionalInstructions?: string + exportAs?: 'pdf' | 'pptx' + folderIds?: string + textAmount?: 'brief' | 'medium' | 'detailed' | 'extensive' + textTone?: string + textAudience?: string + textLanguage?: string + imageSource?: + | 'aiGenerated' + | 'pictographic' + | 'unsplash' + | 'webAllImages' + | 'webFreeToUse' + | 'webFreeToUseCommercially' + | 'giphy' + | 'placeholder' + | 'noImages' + imageModel?: string + imageStyle?: string +} + +/** + * Parameters for the Generate from Template tool. + */ +export interface GammaGenerateFromTemplateParams extends GammaBaseParams { + gammaId: string + prompt: string + themeId?: string + exportAs?: 'pdf' | 'pptx' + folderIds?: string + imageSource?: + | 'aiGenerated' + | 'pictographic' + | 'unsplash' + | 'webAllImages' + | 'webFreeToUse' + | 'webFreeToUseCommercially' + | 'giphy' + | 'placeholder' + | 'noImages' + imageModel?: string + imageStyle?: string +} + +/** + * Parameters for the Check Generation Status tool. + */ +export interface GammaCheckStatusParams extends GammaBaseParams { + generationId: string +} + +/** + * Parameters for the List Themes tool. + */ +export interface GammaListThemesParams extends GammaBaseParams { + query?: string + limit?: number + after?: string +} + +/** + * Parameters for the List Folders tool. + */ +export interface GammaListFoldersParams extends GammaBaseParams { + query?: string + limit?: number + after?: string +} + +/** + * Response for the Generate tool. + */ +export interface GammaGenerateResponse extends ToolResponse { + output: { + generationId: string + } +} + +/** + * Response for the Generate from Template tool. + */ +export interface GammaGenerateFromTemplateResponse extends ToolResponse { + output: { + generationId: string + } +} + +/** + * Response for the Check Status tool. + */ +export interface GammaCheckStatusResponse extends ToolResponse { + output: { + generationId: string + status: 'pending' | 'completed' | 'failed' + gammaUrl: string | null + credits?: { + deducted: number | null + remaining: number | null + } + error?: { + message: string | null + statusCode: number | null + } + } +} + +/** + * Theme object from the Gamma API. + */ +export interface GammaTheme { + id: string + name: string + type: string + colorKeywords: string[] + toneKeywords: string[] +} + +/** + * Response for the List Themes tool. + */ +export interface GammaListThemesResponse extends ToolResponse { + output: { + themes: GammaTheme[] + hasMore: boolean + nextCursor: string | null + } +} + +/** + * Folder object from the Gamma API. + */ +export interface GammaFolder { + id: string + name: string +} + +/** + * Response for the List Folders tool. + */ +export interface GammaListFoldersResponse extends ToolResponse { + output: { + folders: GammaFolder[] + hasMore: boolean + nextCursor: string | null + } +} + +export type GammaResponse = + | GammaGenerateResponse + | GammaGenerateFromTemplateResponse + | GammaCheckStatusResponse + | GammaListThemesResponse + | GammaListFoldersResponse diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 4bcbc9a13a..aa57db5bb5 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -414,6 +414,13 @@ import { firefliesUploadAudioTool, } from '@/tools/fireflies' import { functionExecuteTool } from '@/tools/function' +import { + gammaCheckStatusTool, + gammaGenerateFromTemplateTool, + gammaGenerateTool, + gammaListFoldersTool, + gammaListThemesTool, +} from '@/tools/gamma' import { githubAddAssigneesTool, githubAddAssigneesV2Tool, @@ -2159,6 +2166,11 @@ export const tools: Record = { huggingface_chat: huggingfaceChatTool, llm_chat: llmChatTool, function_execute: functionExecuteTool, + gamma_generate: gammaGenerateTool, + gamma_generate_from_template: gammaGenerateFromTemplateTool, + gamma_check_status: gammaCheckStatusTool, + gamma_list_themes: gammaListThemesTool, + gamma_list_folders: gammaListFoldersTool, vision_tool: visionTool, vision_tool_v2: visionToolV2, file_parser: fileParseTool, From 1b330d849da86a20b2ffd189d7fdfe49bc2cd111 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 26 Feb 2026 17:27:08 -0800 Subject: [PATCH 2/5] fix(gamma): address PR review comments - Make credits/error conditionally included in check_status response to avoid always-truthy objects - Replace full wordmark SVG with square "G" letterform for proper rendering in icon slots --- apps/docs/components/icons.tsx | 18 +------------- apps/sim/components/icons.tsx | 18 +------------- apps/sim/tools/gamma/check_status.ts | 35 ++++++++++++++++------------ 3 files changed, 22 insertions(+), 49 deletions(-) diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 6531501ee4..c178dd9faa 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -528,27 +528,11 @@ export function SlackMonoIcon(props: SVGProps) { export function GammaIcon(props: SVGProps) { return ( - + - - - - ) } diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 6531501ee4..c178dd9faa 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -528,27 +528,11 @@ export function SlackMonoIcon(props: SVGProps) { export function GammaIcon(props: SVGProps) { return ( - + - - - - ) } diff --git a/apps/sim/tools/gamma/check_status.ts b/apps/sim/tools/gamma/check_status.ts index ba005038bc..32d7dbb63a 100644 --- a/apps/sim/tools/gamma/check_status.ts +++ b/apps/sim/tools/gamma/check_status.ts @@ -34,22 +34,27 @@ export const checkStatusTool: ToolConfig { const data = await response.json() - return { - success: true, - output: { - generationId: data.generationId ?? '', - status: data.status ?? 'pending', - gammaUrl: data.gammaUrl ?? null, - credits: { - deducted: data.credits?.deducted ?? null, - remaining: data.credits?.remaining ?? null, - }, - error: { - message: data.error?.message ?? null, - statusCode: data.error?.statusCode ?? null, - }, - }, + const output: Record = { + generationId: data.generationId ?? '', + status: data.status ?? 'pending', + gammaUrl: data.gammaUrl ?? null, + } + + if (data.credits) { + output.credits = { + deducted: data.credits.deducted ?? null, + remaining: data.credits.remaining ?? null, + } + } + + if (data.error) { + output.error = { + message: data.error.message ?? null, + statusCode: data.error.statusCode ?? null, + } } + + return { success: true, output } }, outputs: { From c166e7ff1a33ae9acf6cccf677fc280b80d63a3d Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 26 Feb 2026 18:42:06 -0800 Subject: [PATCH 3/5] fix(gamma): remove imageSource from generate_from_template endpoint The from-template API only accepts imageOptions.model and imageOptions.style, not imageOptions.source (image source is inherited from the template). --- apps/sim/blocks/blocks/gamma.ts | 2 +- apps/sim/tools/gamma/generate_from_template.ts | 8 -------- apps/sim/tools/gamma/types.ts | 10 ---------- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/sim/blocks/blocks/gamma.ts b/apps/sim/blocks/blocks/gamma.ts index 2e66748188..27aad52221 100644 --- a/apps/sim/blocks/blocks/gamma.ts +++ b/apps/sim/blocks/blocks/gamma.ts @@ -161,7 +161,7 @@ Return ONLY the dimension value string, nothing else.`, { label: 'No Images', id: 'noImages' }, ], value: () => 'aiGenerated', - condition: { field: 'operation', value: ['generate', 'generate_from_template'] }, + condition: { field: 'operation', value: 'generate' }, mode: 'advanced', }, { diff --git a/apps/sim/tools/gamma/generate_from_template.ts b/apps/sim/tools/gamma/generate_from_template.ts index 1d62cb31d5..97b682c71f 100644 --- a/apps/sim/tools/gamma/generate_from_template.ts +++ b/apps/sim/tools/gamma/generate_from_template.ts @@ -50,13 +50,6 @@ export const generateFromTemplateTool: ToolConfig< visibility: 'user-or-llm', description: 'Comma-separated folder IDs to store the generated gamma in', }, - imageSource: { - type: 'string', - required: false, - visibility: 'user-or-llm', - description: - 'Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages', - }, imageModel: { type: 'string', required: false, @@ -92,7 +85,6 @@ export const generateFromTemplateTool: ToolConfig< } const imageOptions: Record = {} - if (params.imageSource) imageOptions.source = params.imageSource if (params.imageModel) imageOptions.model = params.imageModel if (params.imageStyle) imageOptions.style = params.imageStyle if (Object.keys(imageOptions).length > 0) body.imageOptions = imageOptions diff --git a/apps/sim/tools/gamma/types.ts b/apps/sim/tools/gamma/types.ts index e96114b4a0..56fcab7a79 100644 --- a/apps/sim/tools/gamma/types.ts +++ b/apps/sim/tools/gamma/types.ts @@ -48,16 +48,6 @@ export interface GammaGenerateFromTemplateParams extends GammaBaseParams { themeId?: string exportAs?: 'pdf' | 'pptx' folderIds?: string - imageSource?: - | 'aiGenerated' - | 'pictographic' - | 'unsplash' - | 'webAllImages' - | 'webFreeToUse' - | 'webFreeToUseCommercially' - | 'giphy' - | 'placeholder' - | 'noImages' imageModel?: string imageStyle?: string } From f12e8066a6c3ab80e8e64adf8c1aeeda5eb8a792 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 26 Feb 2026 18:46:32 -0800 Subject: [PATCH 4/5] fix(gamma): use typed output in check_status transformResponse --- apps/sim/tools/gamma/check_status.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/tools/gamma/check_status.ts b/apps/sim/tools/gamma/check_status.ts index 32d7dbb63a..f360501b8a 100644 --- a/apps/sim/tools/gamma/check_status.ts +++ b/apps/sim/tools/gamma/check_status.ts @@ -31,10 +31,10 @@ export const checkStatusTool: ToolConfig { + transformResponse: async (response: Response): Promise => { const data = await response.json() - const output: Record = { + const output: GammaCheckStatusResponse['output'] = { generationId: data.generationId ?? '', status: data.status ?? 'pending', gammaUrl: data.gammaUrl ?? null, From eaf244f7a077a8e91ba2756e0f1fef849f4e9829 Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 26 Feb 2026 19:06:47 -0800 Subject: [PATCH 5/5] regen docs --- apps/docs/content/docs/en/tools/gamma.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/docs/content/docs/en/tools/gamma.mdx b/apps/docs/content/docs/en/tools/gamma.mdx index c05d187cf4..f62b2232a5 100644 --- a/apps/docs/content/docs/en/tools/gamma.mdx +++ b/apps/docs/content/docs/en/tools/gamma.mdx @@ -79,7 +79,6 @@ Generate a new Gamma by adapting an existing template with a prompt. | `themeId` | string | No | Custom Gamma workspace theme ID to apply | | `exportAs` | string | No | Automatically export the generated gamma as pdf or pptx | | `folderIds` | string | No | Comma-separated folder IDs to store the generated gamma in | -| `imageSource` | string | No | Where to source images: aiGenerated, pictographic, unsplash, webAllImages, webFreeToUse, webFreeToUseCommercially, giphy, placeholder, or noImages | | `imageModel` | string | No | AI image generation model to use when imageSource is aiGenerated | | `imageStyle` | string | No | Style directive for AI-generated images, e.g. "watercolor", "photorealistic" \(max 500 chars\) |