@bubblelab/bubble-core 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bubble-bundle.d.ts +625 -296
- package/dist/bubble-factory.d.ts.map +1 -1
- package/dist/bubble-factory.js +13 -9
- package/dist/bubble-factory.js.map +1 -1
- package/dist/bubbles/service-bubble/ai-agent.d.ts +135 -117
- package/dist/bubbles/service-bubble/ai-agent.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/ai-agent.js +273 -95
- package/dist/bubbles/service-bubble/ai-agent.js.map +1 -1
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +805 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.js +131 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +485 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.js +176 -0
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +302 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.js +138 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +642 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.js +123 -0
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/api-scraper.schema.d.ts +370 -0
- package/dist/bubbles/service-bubble/apify/api-scraper.schema.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/api-scraper.schema.js +14 -0
- package/dist/bubbles/service-bubble/apify/api-scraper.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +1770 -0
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js +38 -0
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/apify.d.ts +143 -0
- package/dist/bubbles/service-bubble/apify/apify.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/apify.js +276 -0
- package/dist/bubbles/service-bubble/apify/apify.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/index.d.ts +4 -0
- package/dist/bubbles/service-bubble/apify/index.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/index.js +3 -0
- package/dist/bubbles/service-bubble/apify/index.js.map +1 -0
- package/dist/bubbles/service-bubble/apify/types.d.ts +7 -0
- package/dist/bubbles/service-bubble/apify/types.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify/types.js +6 -0
- package/dist/bubbles/service-bubble/apify/types.js.map +1 -0
- package/dist/bubbles/service-bubble/apify.d.ts +136 -0
- package/dist/bubbles/service-bubble/apify.d.ts.map +1 -0
- package/dist/bubbles/service-bubble/apify.js +282 -0
- package/dist/bubbles/service-bubble/apify.js.map +1 -0
- package/dist/bubbles/service-bubble/gmail.d.ts +52 -52
- package/dist/bubbles/service-bubble/google-calendar.d.ts +24 -24
- package/dist/bubbles/service-bubble/google-drive.d.ts +68 -68
- package/dist/bubbles/service-bubble/google-sheets.d.ts +64 -64
- package/dist/bubbles/service-bubble/hello-world.d.ts +4 -4
- package/dist/bubbles/service-bubble/http.d.ts +4 -4
- package/dist/bubbles/service-bubble/postgresql.d.ts +12 -12
- package/dist/bubbles/service-bubble/resend.d.ts +13 -13
- package/dist/bubbles/service-bubble/resend.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/resend.js +16 -5
- package/dist/bubbles/service-bubble/resend.js.map +1 -1
- package/dist/bubbles/service-bubble/slack.d.ts +462 -462
- package/dist/bubbles/service-bubble/storage.d.ts +32 -32
- package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts +14 -1
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.js +85 -39
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts +435 -0
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/instagram-tool.js +474 -0
- package/dist/bubbles/tool-bubble/instagram-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +2136 -0
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts.map +1 -0
- package/dist/bubbles/tool-bubble/linkedin-tool.js +608 -0
- package/dist/bubbles/tool-bubble/linkedin-tool.js.map +1 -0
- package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +14 -14
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +6 -6
- package/dist/bubbles/tool-bubble/research-agent-tool.js +1 -1
- package/dist/bubbles/tool-bubble/research-agent-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/tool-template.d.ts +4 -4
- package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/web-extract-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts +16 -16
- package/dist/bubbles/tool-bubble/web-scrape-tool.js +1 -1
- package/dist/bubbles/tool-bubble/web-scrape-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/web-search-tool.d.ts +10 -10
- package/dist/bubbles/tool-bubble/web-search-tool.js +1 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js +5 -0
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/database-analyzer.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +78 -78
- package/dist/bubbles/workflow-bubble/generate-document.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/generate-document.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +50 -50
- package/dist/bubbles/workflow-bubble/parse-document.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/parse-document.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +42 -42
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js +1 -4
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +36 -36
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +40 -40
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js +1 -1
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +34 -34
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.js +1 -1
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.js.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +10 -10
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts.map +1 -1
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js +1 -2
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js.map +1 -1
- package/dist/bubbles.json +474 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/logging/BubbleLogger.d.ts +11 -0
- package/dist/logging/BubbleLogger.d.ts.map +1 -1
- package/dist/logging/BubbleLogger.js +69 -22
- package/dist/logging/BubbleLogger.js.map +1 -1
- package/dist/logging/StreamingBubbleLogger.d.ts.map +1 -1
- package/dist/logging/StreamingBubbleLogger.js +18 -11
- package/dist/logging/StreamingBubbleLogger.js.map +1 -1
- package/dist/types/ai-models.d.ts +1 -1
- package/dist/types/ai-models.d.ts.map +1 -1
- package/dist/types/ai-models.js +4 -0
- package/dist/types/ai-models.js.map +1 -1
- package/dist/types/api-scraper.schema.d.ts +453 -0
- package/dist/types/api-scraper.schema.d.ts.map +1 -0
- package/dist/types/api-scraper.schema.js +160 -0
- package/dist/types/api-scraper.schema.js.map +1 -0
- package/dist/types/available-tools.d.ts +1 -1
- package/dist/types/available-tools.d.ts.map +1 -1
- package/dist/types/available-tools.js +2 -0
- package/dist/types/available-tools.js.map +1 -1
- package/dist/types/base-bubble-class.d.ts +5 -0
- package/dist/types/base-bubble-class.d.ts.map +1 -1
- package/dist/types/base-bubble-class.js +18 -3
- package/dist/types/base-bubble-class.js.map +1 -1
- package/dist/types/bubble.d.ts +2 -3
- package/dist/types/bubble.d.ts.map +1 -1
- package/dist/types/service-bubble-class.d.ts +4 -4
- package/dist/types/service-bubble-class.d.ts.map +1 -1
- package/dist/types/service-bubble-class.js +6 -7
- package/dist/types/service-bubble-class.js.map +1 -1
- package/dist/types/tool-bubble-class.d.ts.map +1 -1
- package/dist/types/tool-bubble-class.js +9 -1
- package/dist/types/tool-bubble-class.js.map +1 -1
- package/dist/utils/agent-formatter.d.ts +17 -0
- package/dist/utils/agent-formatter.d.ts.map +1 -0
- package/dist/utils/agent-formatter.js +139 -0
- package/dist/utils/agent-formatter.js.map +1 -0
- package/dist/utils/json-parsing.d.ts +1 -0
- package/dist/utils/json-parsing.d.ts.map +1 -1
- package/dist/utils/json-parsing.js +205 -32
- package/dist/utils/json-parsing.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"generatedAt": "2025-10-24T06:48:30.042Z",
|
|
4
|
+
"totalCount": 35,
|
|
5
|
+
"bubbles": [
|
|
6
|
+
{
|
|
7
|
+
"name": "hello-world",
|
|
8
|
+
"alias": "hello",
|
|
9
|
+
"type": "service",
|
|
10
|
+
"shortDescription": "Simple hello world bubble for testing purposes",
|
|
11
|
+
"useCase": "- Testing the bubble execution system",
|
|
12
|
+
"inputSchema": "{\n name: string // Name to include in the greeting message,\n message: string | undefined // Custom greeting message,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime)\n}",
|
|
13
|
+
"outputSchema": "{\n greeting: string // The generated greeting message,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
14
|
+
"usageExample": "// Example usage of hello-world bubble\nconst helloWorld = new HelloWorldBubble({\n name: \"example string\", // Name to include in the greeting message,\n message: \"Hello from NodeX!\" // default, // Custom greeting message,\n});\n\nconst result = await helloWorld.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// greeting: string // The generated greeting message,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
15
|
+
"requiredCredentials": []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "ai-agent",
|
|
19
|
+
"alias": "agent",
|
|
20
|
+
"type": "service",
|
|
21
|
+
"shortDescription": "AI agent with LangGraph for tool-enabled conversations, multimodal support, and JSON mode",
|
|
22
|
+
"useCase": "- Add tools to enhance the AI agent's capabilities (web-search-tool, web-scrape-tool)",
|
|
23
|
+
"inputSchema": "{\n message: string // The message or question to send to the AI agent,\n images: DiscriminatedUnion[] // Array of base64 encoded images to include with the message (for multimodal AI models). Example: [{type: \"base64\", data: \"base64...\", mimeType: \"image/png\", description: \"A beautiful image of a cat\"}] or [{type: \"url\", url: \"https://example.com/image.png\", description: \"A beautiful image of a cat\"}],\n systemPrompt: string // System prompt that defines the AI agents behavior and personality,\n name: string | undefined // A friendly name for the AI agent,\n model: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\", temperature: number, maxTokens: number | undefined, jsonMode: boolean } // AI model configuration including provider, temperature, and tokens. For model unless otherwise specified, use google/gemini-2.5-flash as default. Use google/gemini-2.5-flash-image-preview to edit and generate images.,\n tools: { name: \"web-search-tool\" | \"web-scrape-tool\" | \"web-crawl-tool\" | \"web-extract-tool\" | \"research-agent-tool\" | \"reddit-scrape-tool\" | \"instagram-tool\" | \"list-bubbles-tool\" | \"get-bubble-details-tool\" | \"bubbleflow-validation-tool\" | \"chart-js-tool\" | \"sql-query-tool\", credentials: Record<string, string> | undefined, config: Record<string, unknown> | undefined }[] // Array of pre-registered tools the AI agent can use. Can be tool types (web-search-tool, web-scrape-tool, web-crawl-tool, web-extract-tool, instagram-tool). If using image models, set the tools to [],\n customTools: { name: string, description: string, schema: Record<string, unknown>, func: unknown }[] | undefined // Array of custom runtime-defined tools with their own schemas and functions. Use this to add domain-specific tools without pre-registration. Example: [{ name: \"calculate-tax\", description: \"Calculates sales tax\", schema: { amount: z.number() }, func: async (input) => {...} }],\n maxIterations: number // Maximum number of iterations for the agent workflow, 2 iterations per turn of conversation,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime),\n streaming: boolean // Enable real-time streaming of tokens, tool calls, and iteration progress\n}",
|
|
24
|
+
"outputSchema": "{\n response: string // The AI agents final response to the user message. For text responses, returns plain text or JSON string. For image generation models (like gemini-2.5-flash-image-preview), returns base64-encoded image data with data URI format (data:image/png;base64,...),\n toolCalls: { tool: string, input: unknown, output: unknown }[] // Array of tool calls made during the conversation,\n iterations: number // Number of back-and-forth iterations in the agent workflow,\n error: string // Error message of the run, undefined if successful,\n success: boolean // Whether the agent execution completed successfully\n}",
|
|
25
|
+
"usageExample": "// Example usage of ai-agent bubble\nconst aiAgent = new AiAgentBubble({\n message: \"example string\", // The message or question to send to the AI agent,\n images: [{ type: \"base64\" // default, data: \"example string\", mimeType: \"image/png\" // default, description: \"example string\" }] // example for array, // Array of base64 encoded images to include with the message (for multimodal AI models). Example: [{type: \"base64\", data: \"base64...\", mimeType: \"image/png\", description: \"A beautiful image of a cat\"}] or [{type: \"url\", url: \"https://example.com/image.png\", description: \"A beautiful image of a cat\"}],\n systemPrompt: \"You are a helpful AI assistant\" // default, // System prompt that defines the AI agents behavior and personality,\n name: \"AI Agent\" // default, // A friendly name for the AI agent,\n model: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use (format: provider/model-name)., temperature: 1 // default // Temperature for response randomness (0 = deterministic, 2 = very random), maxTokens: 40000 // default // Maximum number of tokens to generate in response, keep at default of 40000 unless the response is expected to be certain length, jsonMode: false // default // When true, strips markdown formatting and returns clean JSON response } // structure, // AI model configuration including provider, temperature, and tokens. For model unless otherwise specified, use google/gemini-2.5-flash as default. Use google/gemini-2.5-flash-image-preview to edit and generate images.,\n tools: [{\"name\":\"web-search-tool\",\"config\":{\"maxResults\":5}}] // default, // Array of pre-registered tools the AI agent can use. Can be tool types (web-search-tool, web-scrape-tool, web-crawl-tool, web-extract-tool, instagram-tool). If using image models, set the tools to [],\n customTools: [{ name: \"example string\" // Unique name for your custom tool (e.g., \"calculate-tax\"), description: \"example string\" // Description of what the tool does - helps the AI know when to use it, schema: {} // record/object with string keys // Zod schema object defining the tool parameters. Example: { amount: z.number().describe(\"Amount to calculate tax on\"), rate: z.number().describe(\"Tax rate\") } }] // example for array, // Array of custom runtime-defined tools with their own schemas and functions. Use this to add domain-specific tools without pre-registration. Example: [{ name: \"calculate-tax\", description: \"Calculates sales tax\", schema: { amount: z.number() }, func: async (input) => {...} }],\n maxIterations: 10 // default, // Maximum number of iterations for the agent workflow, 2 iterations per turn of conversation,\n streaming: false // default, // Enable real-time streaming of tokens, tool calls, and iteration progress,\n});\n\nconst result = await aiAgent.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// response: string // The AI agents final response to the user message. For text responses, returns plain text or JSON string. For image generation models (like gemini-2.5-flash-image-preview), returns base64-encoded image data with data URI format (data:image/png;base64,...),\n// toolCalls: { tool: string, input: unknown, output: unknown }[] // Array of tool calls made during the conversation,\n// iterations: number // Number of back-and-forth iterations in the agent workflow,\n// error: string // Error message of the run, undefined if successful,\n// success: boolean // Whether the agent execution completed successfully\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
26
|
+
"requiredCredentials": [
|
|
27
|
+
"OPENAI_CRED",
|
|
28
|
+
"GOOGLE_GEMINI_CRED",
|
|
29
|
+
"ANTHROPIC_CRED",
|
|
30
|
+
"FIRECRAWL_API_KEY",
|
|
31
|
+
"OPENROUTER_CRED"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "postgresql",
|
|
36
|
+
"alias": "pg",
|
|
37
|
+
"type": "service",
|
|
38
|
+
"shortDescription": "Execute PostgreSQL queries with operation validation",
|
|
39
|
+
"useCase": "- Data retrieval with SELECT queries",
|
|
40
|
+
"inputSchema": "{\n ignoreSSL: boolean // Ignore SSL certificate errors when connecting to the database,\n query: unknown // SQL query to execute against the PostgreSQL database (use parameterized queries with $1, $2, etc.),\n allowedOperations: \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\" | \"WITH\" | \"EXPLAIN\" | \"ANALYZE\" | \"SHOW\" | \"DESCRIBE\" | \"DESC\" | \"CREATE\"[] // List of allowed SQL operations for security (defaults to read-only operations),\n parameters: unknown[] | undefined // Parameters for parameterized queries (e.g., [value1, value2] for $1, $2),\n timeout: number // Query timeout in milliseconds (default: 30 seconds, max recommended: 300000),\n maxRows: number // Maximum number of rows to return to prevent large result sets (default: 1000),\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime)\n}",
|
|
41
|
+
"outputSchema": "{\n rows: Record<string, unknown>[] // Array of result rows, each row is an object with column names as keys,\n rowCount: number | null // Number of rows affected by the query (null for SELECT queries),\n command: string // SQL command that was executed (SELECT, INSERT, UPDATE, DELETE),\n fields: { name: string, dataTypeID: number }[] | undefined // Metadata about the columns returned by the query,\n executionTime: number // Query execution time in milliseconds,\n success: boolean // Whether the query executed successfully,\n error: string // Error message if query execution failed (empty string if successful),\n cleanedJSONString: string // Clean JSON string representation of the row data, suitable for AI prompts and integrations\n}",
|
|
42
|
+
"usageExample": "// Example usage of postgresql bubble\nconst postgresql = new PostgresqlBubble({\n ignoreSSL: true // default, // Ignore SSL certificate errors when connecting to the database,\n allowedOperations: [\"SELECT\",\"WITH\",\"EXPLAIN\",\"ANALYZE\",\"SHOW\",\"DESCRIBE\",\"DESC\"] // default, // List of allowed SQL operations for security (defaults to read-only operations),\n parameters: [] // default, // Parameters for parameterized queries (e.g., [value1, value2] for $1, $2),\n timeout: 30000 // default, // Query timeout in milliseconds (default: 30 seconds, max recommended: 300000),\n maxRows: 1000 // default, // Maximum number of rows to return to prevent large result sets (default: 1000),\n});\n\nconst result = await postgresql.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// rows: Record<string, unknown>[] // Array of result rows, each row is an object with column names as keys,\n// rowCount: number | null // Number of rows affected by the query (null for SELECT queries),\n// command: string // SQL command that was executed (SELECT, INSERT, UPDATE, DELETE),\n// fields: { name: string, dataTypeID: number }[] | undefined // Metadata about the columns returned by the query,\n// executionTime: number // Query execution time in milliseconds,\n// success: boolean // Whether the query executed successfully,\n// error: string // Error message if query execution failed (empty string if successful),\n// cleanedJSONString: string // Clean JSON string representation of the row data, suitable for AI prompts and integrations\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
43
|
+
"requiredCredentials": [
|
|
44
|
+
"DATABASE_CRED"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "slack",
|
|
49
|
+
"alias": "slack",
|
|
50
|
+
"type": "service",
|
|
51
|
+
"shortDescription": "Slack integration for messaging and workspace management",
|
|
52
|
+
"useCase": "- Send messages to channels or direct messages",
|
|
53
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
54
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
55
|
+
"usageExample": "// Send Message example\nconst slack_send_message = new SlackBubble({\n operation: \"send_message\", // Send a message to a Slack channel or DM\n channel: \"example string\", // Channel ID (e.g., C1234567890), channel name (e.g., general or #general), or user ID for DM\n text: \"example string\", // Message text content\n username: \"example string\", // Override bot username for this message\n icon_emoji: \"example string\", // Override bot icon with emoji (e.g., :robot_face:)\n icon_url: \"example string\", // Override bot icon with custom image URL\n attachments: [{ color: \"example string\" // Color bar accent (hex color or good/warning/danger), pretext: \"example string\" // Text that appears before the main attachment content, author_name: \"example string\" // Author name displayed at the top, author_link: \"example string\" // URL to link the author name, author_icon: \"example string\" // Author icon image URL, title: \"example string\" // Attachment title text, title_link: \"example string\" // URL to link the title, text: \"example string\" // Main attachment text content, fields: [{ title: \"example string\" // Field title, value: \"example string\" // Field value, short: true // Whether field should be displayed side-by-side }] // Array of field objects for structured data, image_url: \"example string\" // URL of image to display, thumb_url: \"example string\" // URL of thumbnail image, footer: \"example string\" // Footer text, footer_icon: \"example string\" // Footer icon URL, ts: 42 // Timestamp for the attachment }], // Legacy message attachments\n blocks: [{ type: \"example string\" // Block element type (section, divider, button, etc.), text: { type: \"plain_text\" // options: \"plain_text\", \"mrkdwn\" // Text formatting type, text: \"example string\" // The actual text content, emoji: true, verbatim: true } // Text object for the block element, elements: [{ type: \"plain_text\" // options: \"plain_text\", \"mrkdwn\", \"image\" // Element type, text: \"example string\" // Text content, image_url: \"example string\" // Image URL for image elements, alt_text: \"example string\" // Alt text for image elements, emoji: true, verbatim: true }] // Elements array for context blocks }], // Block Kit structured message blocks\n thread_ts: \"example string\", // Timestamp of parent message to reply in thread\n reply_broadcast: false // default, // Broadcast thread reply to channel\n unfurl_links: true // default, // Enable automatic link unfurling\n unfurl_media: true // default, // Enable automatic media unfurling\n});\n\nconst result = await slack_send_message.action();\n// outputSchema for result.data when operation === 'send_message':\n// {\n// operation: \"send_message\" // Send a message to a Slack channel or DM,\n// ok: boolean // Whether the Slack API call was successful,\n// channel: string | undefined // Channel ID where the message was sent,\n// ts: string | undefined // Timestamp of the sent message,\n// message: { type: string, ts: string, user: string | undefined, bot_id: string | undefined, bot_profile: { name: string | undefined } | undefined, username: string | undefined, text: string | undefined, thread_ts: string | undefined, parent_user_id: string | undefined, reply_count: number | undefined, reply_users_count: number | undefined, latest_reply: string | undefined, reply_users: string[] | undefined, is_locked: boolean | undefined, subscribed: boolean | undefined, attachments: unknown[] | undefined, blocks: unknown[] | undefined, reactions: { name: string, users: string[], count: number }[] | undefined } | undefined // Details of the sent message,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// List Channels example\nconst slack_list_channels = new SlackBubble({\n operation: \"list_channels\", // List all channels in the Slack workspace\n types: [\"public_channel\",\"private_channel\"] // default, // Types of channels to include in results\n exclude_archived: true // default, // Exclude archived channels from results\n limit: 50 // default, // Maximum number of channels to return (1-1000)\n cursor: \"example string\", // Cursor for pagination to get next set of results\n});\n\nconst result = await slack_list_channels.action();\n// outputSchema for result.data when operation === 'list_channels':\n// {\n// operation: \"list_channels\" // List all channels in the Slack workspace,\n// ok: boolean // Whether the Slack API call was successful,\n// channels: { id: string, name: string, is_channel: boolean | undefined, is_group: boolean | undefined, is_im: boolean | undefined, is_mpim: boolean | undefined, is_private: boolean | undefined, created: number, is_archived: boolean, is_general: boolean | undefined, unlinked: number | undefined, name_normalized: string | undefined, is_shared: boolean | undefined, is_ext_shared: boolean | undefined, is_org_shared: boolean | undefined, shared_team_ids: string[] | undefined, pending_shared: string[] | undefined, pending_connected_team_ids: string[] | undefined, is_pending_ext_shared: boolean | undefined, is_member: boolean | undefined, is_open: boolean | undefined, topic: { value: string, creator: string, last_set: number } | undefined, purpose: { value: string, creator: string, last_set: number } | undefined, num_members: number | undefined }[] | undefined // Array of channel objects,\n// response_metadata: { next_cursor: string } | undefined // Metadata for pagination,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Get Channel Info example\nconst slack_get_channel_info = new SlackBubble({\n operation: \"get_channel_info\", // Get detailed information about a specific channel\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general)\n include_locale: false // default, // Include locale information in the response\n});\n\nconst result = await slack_get_channel_info.action();\n// outputSchema for result.data when operation === 'get_channel_info':\n// {\n// operation: \"get_channel_info\" // Get detailed information about a specific channel,\n// ok: boolean // Whether the Slack API call was successful,\n// channel: { id: string, name: string, is_channel: boolean | undefined, is_group: boolean | undefined, is_im: boolean | undefined, is_mpim: boolean | undefined, is_private: boolean | undefined, created: number, is_archived: boolean, is_general: boolean | undefined, unlinked: number | undefined, name_normalized: string | undefined, is_shared: boolean | undefined, is_ext_shared: boolean | undefined, is_org_shared: boolean | undefined, shared_team_ids: string[] | undefined, pending_shared: string[] | undefined, pending_connected_team_ids: string[] | undefined, is_pending_ext_shared: boolean | undefined, is_member: boolean | undefined, is_open: boolean | undefined, topic: { value: string, creator: string, last_set: number } | undefined, purpose: { value: string, creator: string, last_set: number } | undefined, num_members: number | undefined } | undefined // Channel information object,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Get User Info example\nconst slack_get_user_info = new SlackBubble({\n operation: \"get_user_info\", // Get detailed information about a specific user\n user: \"example string\", // User ID to get information about\n include_locale: false // default, // Include locale information in the response\n});\n\nconst result = await slack_get_user_info.action();\n// outputSchema for result.data when operation === 'get_user_info':\n// {\n// operation: \"get_user_info\" // Get detailed information about a specific user,\n// ok: boolean // Whether the Slack API call was successful,\n// user: { id: string, team_id: string | undefined, name: string, deleted: boolean | undefined, color: string | undefined, real_name: string | undefined, tz: string | undefined, tz_label: string | undefined, tz_offset: number | undefined, profile: { title: string | undefined, phone: string | undefined, skype: string | undefined, real_name: string | undefined, real_name_normalized: string | undefined, display_name: string | undefined, display_name_normalized: string | undefined, fields: Record<string, unknown> | undefined, status_text: string | undefined, status_emoji: string | undefined, status_expiration: number | undefined, avatar_hash: string | undefined, image_original: string | undefined, is_custom_image: boolean | undefined, email: string | undefined, first_name: string | undefined, last_name: string | undefined, image_24: string | undefined, image_32: string | undefined, image_48: string | undefined, image_72: string | undefined, image_192: string | undefined, image_512: string | undefined, image_1024: string | undefined } | undefined, is_admin: boolean | undefined, is_owner: boolean | undefined, is_primary_owner: boolean | undefined, is_restricted: boolean | undefined, is_ultra_restricted: boolean | undefined, is_bot: boolean | undefined, is_app_user: boolean | undefined, updated: number | undefined, has_2fa: boolean | undefined } | undefined // User information object,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// List Users example\nconst slack_list_users = new SlackBubble({\n operation: \"list_users\", // List all users in the Slack workspace\n limit: 50 // default, // Maximum number of users to return (1-1000)\n cursor: \"example string\", // Cursor for pagination to get next set of results\n include_locale: false // default, // Include locale information in the response\n});\n\nconst result = await slack_list_users.action();\n// outputSchema for result.data when operation === 'list_users':\n// {\n// operation: \"list_users\" // List all users in the Slack workspace,\n// ok: boolean // Whether the Slack API call was successful,\n// members: { id: string, team_id: string | undefined, name: string, deleted: boolean | undefined, color: string | undefined, real_name: string | undefined, tz: string | undefined, tz_label: string | undefined, tz_offset: number | undefined, profile: { title: string | undefined, phone: string | undefined, skype: string | undefined, real_name: string | undefined, real_name_normalized: string | undefined, display_name: string | undefined, display_name_normalized: string | undefined, fields: Record<string, unknown> | undefined, status_text: string | undefined, status_emoji: string | undefined, status_expiration: number | undefined, avatar_hash: string | undefined, image_original: string | undefined, is_custom_image: boolean | undefined, email: string | undefined, first_name: string | undefined, last_name: string | undefined, image_24: string | undefined, image_32: string | undefined, image_48: string | undefined, image_72: string | undefined, image_192: string | undefined, image_512: string | undefined, image_1024: string | undefined } | undefined, is_admin: boolean | undefined, is_owner: boolean | undefined, is_primary_owner: boolean | undefined, is_restricted: boolean | undefined, is_ultra_restricted: boolean | undefined, is_bot: boolean | undefined, is_app_user: boolean | undefined, updated: number | undefined, has_2fa: boolean | undefined }[] | undefined // Array of user objects,\n// response_metadata: { next_cursor: string } | undefined // Metadata for pagination,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Get Conversation History example\nconst slack_get_conversation_history = new SlackBubble({\n operation: \"get_conversation_history\", // Retrieve message history from a channel or direct message\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general)\n latest: \"example string\", // End of time range of messages to include (timestamp)\n oldest: \"example string\", // Start of time range of messages to include (timestamp)\n inclusive: false // default, // Include messages with latest or oldest timestamps in results\n limit: 20 // default, // Maximum number of messages to return (1-1000)\n cursor: \"example string\", // Cursor for pagination to get next set of results\n});\n\nconst result = await slack_get_conversation_history.action();\n// outputSchema for result.data when operation === 'get_conversation_history':\n// {\n// operation: \"get_conversation_history\" // Retrieve message history from a channel or direct message,\n// ok: boolean // Whether the Slack API call was successful,\n// messages: { type: string, ts: string, user: string | undefined, bot_id: string | undefined, bot_profile: { name: string | undefined } | undefined, username: string | undefined, text: string | undefined, thread_ts: string | undefined, parent_user_id: string | undefined, reply_count: number | undefined, reply_users_count: number | undefined, latest_reply: string | undefined, reply_users: string[] | undefined, is_locked: boolean | undefined, subscribed: boolean | undefined, attachments: unknown[] | undefined, blocks: unknown[] | undefined, reactions: { name: string, users: string[], count: number }[] | undefined }[] | undefined // Array of message objects,\n// has_more: boolean | undefined // Whether there are more messages to retrieve,\n// response_metadata: { next_cursor: string } | undefined // Metadata for pagination,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Get Thread Replies example\nconst slack_get_thread_replies = new SlackBubble({\n operation: \"get_thread_replies\", // Retrieve all replies to a thread in a channel\n channel: \"example string\", // Channel ID where the thread exists\n ts: \"example string\", // Timestamp of the parent message to get replies for\n latest: \"example string\", // End of time range of messages to include (timestamp)\n oldest: \"example string\", // Start of time range of messages to include (timestamp)\n inclusive: false // default, // Include messages with latest or oldest timestamps in results\n limit: 100 // default, // Maximum number of messages to return (1-1000)\n cursor: \"example string\", // Cursor for pagination to get next set of results\n});\n\nconst result = await slack_get_thread_replies.action();\n// outputSchema for result.data when operation === 'get_thread_replies':\n// {\n// operation: \"get_thread_replies\" // Retrieve all replies to a thread in a channel,\n// ok: boolean // Whether the Slack API call was successful,\n// messages: { type: string, ts: string, user: string | undefined, bot_id: string | undefined, bot_profile: { name: string | undefined } | undefined, username: string | undefined, text: string | undefined, thread_ts: string | undefined, parent_user_id: string | undefined, reply_count: number | undefined, reply_users_count: number | undefined, latest_reply: string | undefined, reply_users: string[] | undefined, is_locked: boolean | undefined, subscribed: boolean | undefined, attachments: unknown[] | undefined, blocks: unknown[] | undefined, reactions: { name: string, users: string[], count: number }[] | undefined }[] | undefined // Array of message objects in the thread,\n// has_more: boolean | undefined // Whether there are more messages to retrieve,\n// response_metadata: { next_cursor: string } | undefined // Metadata for pagination,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Update Message example\nconst slack_update_message = new SlackBubble({\n operation: \"update_message\", // Update an existing message in a channel\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located\n ts: \"example string\", // Timestamp of the message to update\n text: \"example string\", // New text content for the message\n attachments: [{ color: \"example string\" // Color bar accent (hex color or good/warning/danger), pretext: \"example string\" // Text that appears before the main attachment content, author_name: \"example string\" // Author name displayed at the top, author_link: \"example string\" // URL to link the author name, author_icon: \"example string\" // Author icon image URL, title: \"example string\" // Attachment title text, title_link: \"example string\" // URL to link the title, text: \"example string\" // Main attachment text content, fields: [{ title: \"example string\" // Field title, value: \"example string\" // Field value, short: true // Whether field should be displayed side-by-side }] // Array of field objects for structured data, image_url: \"example string\" // URL of image to display, thumb_url: \"example string\" // URL of thumbnail image, footer: \"example string\" // Footer text, footer_icon: \"example string\" // Footer icon URL, ts: 42 // Timestamp for the attachment }], // New legacy message attachments\n blocks: [{ type: \"example string\" // Block element type (section, divider, button, etc.), text: { type: \"plain_text\" // options: \"plain_text\", \"mrkdwn\" // Text formatting type, text: \"example string\" // The actual text content, emoji: true, verbatim: true } // Text object for the block element, elements: [{ type: \"plain_text\" // options: \"plain_text\", \"mrkdwn\", \"image\" // Element type, text: \"example string\" // Text content, image_url: \"example string\" // Image URL for image elements, alt_text: \"example string\" // Alt text for image elements, emoji: true, verbatim: true }] // Elements array for context blocks }], // New Block Kit structured message blocks\n});\n\nconst result = await slack_update_message.action();\n// outputSchema for result.data when operation === 'update_message':\n// {\n// operation: \"update_message\" // Update an existing message in a channel,\n// ok: boolean // Whether the Slack API call was successful,\n// channel: string | undefined // Channel ID where the message was updated,\n// ts: string | undefined // Timestamp of the updated message,\n// text: string | undefined // Updated text content of the message,\n// message: { type: string, ts: string, user: string | undefined, bot_id: string | undefined, bot_profile: { name: string | undefined } | undefined, username: string | undefined, text: string | undefined, thread_ts: string | undefined, parent_user_id: string | undefined, reply_count: number | undefined, reply_users_count: number | undefined, latest_reply: string | undefined, reply_users: string[] | undefined, is_locked: boolean | undefined, subscribed: boolean | undefined, attachments: unknown[] | undefined, blocks: unknown[] | undefined, reactions: { name: string, users: string[], count: number }[] | undefined } | undefined // Details of the updated message,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Delete Message example\nconst slack_delete_message = new SlackBubble({\n operation: \"delete_message\", // Delete a message from a channel\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located\n ts: \"example string\", // Timestamp of the message to delete\n});\n\nconst result = await slack_delete_message.action();\n// outputSchema for result.data when operation === 'delete_message':\n// {\n// operation: \"delete_message\" // Delete a message from a channel,\n// ok: boolean // Whether the Slack API call was successful,\n// channel: string | undefined // Channel ID where the message was deleted,\n// ts: string | undefined // Timestamp of the deleted message,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Add Reaction example\nconst slack_add_reaction = new SlackBubble({\n operation: \"add_reaction\", // Add an emoji reaction to a message\n name: \"example string\", // Emoji name without colons (e.g., thumbsup, heart)\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located\n timestamp: \"example string\", // Timestamp of the message to react to\n});\n\nconst result = await slack_add_reaction.action();\n// outputSchema for result.data when operation === 'add_reaction':\n// {\n// operation: \"add_reaction\" // Add an emoji reaction to a message,\n// ok: boolean // Whether the Slack API call was successful,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Remove Reaction example\nconst slack_remove_reaction = new SlackBubble({\n operation: \"remove_reaction\", // Remove an emoji reaction from a message\n name: \"example string\", // Emoji name without colons (e.g., thumbsup, heart)\n channel: \"example string\", // Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located\n timestamp: \"example string\", // Timestamp of the message to remove reaction from\n});\n\nconst result = await slack_remove_reaction.action();\n// outputSchema for result.data when operation === 'remove_reaction':\n// {\n// operation: \"remove_reaction\" // Remove an emoji reaction from a message,\n// ok: boolean // Whether the Slack API call was successful,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Upload File example\nconst slack_upload_file = new SlackBubble({\n operation: \"upload_file\", // Upload a file to a Slack channel\n channel: \"example string\", // Channel ID (e.g., C1234567890), channel name (e.g., general or #general), or user ID for DM\n file_path: \"example string\", // Local file path to upload\n filename: \"example string\", // Override filename for the upload\n title: \"example string\", // Title for the file\n initial_comment: \"example string\", // Initial comment to post with the file\n thread_ts: \"example string\", // Timestamp of parent message to upload file in thread\n});\n\nconst result = await slack_upload_file.action();\n// outputSchema for result.data when operation === 'upload_file':\n// {\n// operation: \"upload_file\" // Upload a file to a Slack channel,\n// ok: boolean // Whether the Slack API call was successful,\n// file: { id: string, created: number, timestamp: number, name: string, title: string | undefined, mimetype: string, filetype: string, pretty_type: string, user: string, editable: boolean, size: number, mode: string, is_external: boolean, external_type: string, is_public: boolean, public_url_shared: boolean, display_as_bot: boolean, username: string, url_private: string, url_private_download: string, permalink: string, permalink_public: string | undefined, shares: { public: Record<string, { reply_users: string[], reply_users_count: number, reply_count: number, ts: string, channel_name: string, team_id: string }[]> | undefined, private: Record<string, { reply_users: string[], reply_users_count: number, reply_count: number, ts: string, channel_name: string, team_id: string }[]> | undefined } | undefined, channels: string[] | undefined, groups: string[] | undefined, ims: string[] | undefined, has_rich_preview: boolean | undefined } | undefined // File information object,\n// error: string // Error message if operation failed,\n// success: boolean // Whether the operation was successful\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`slack failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
56
|
+
"requiredCredentials": [
|
|
57
|
+
"SLACK_CRED"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "resend",
|
|
62
|
+
"alias": "resend",
|
|
63
|
+
"type": "service",
|
|
64
|
+
"shortDescription": "Email sending service via Resend API",
|
|
65
|
+
"useCase": "- Send transactional emails with HTML and text content",
|
|
66
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
67
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
68
|
+
"usageExample": "// Send Email example\nconst resend_send_email = new ResendBubble({\n operation: \"send_email\", // Send an email via Resend\n from: \"Bubble Lab Team <welcome@hello.bubblelab.ai>\" // default, // Sender email address, should not be changed from <welcome@hello.bubblelab.ai> if resend account has not been setup with domain verification\n subject: \"example string\", // Email subject line\n text: \"example string\", // Plain text email content\n html: \"example string\", // HTML email content\n scheduled_at: \"example string\", // Schedule email to be sent later (ISO 8601 format or natural language like \"in 1 hour\")\n attachments: [{ filename: \"example string\" // Name of the attached file, content_type: \"example string\" // MIME type of the file, path: \"example string\" // Path where the attachment file is hosted }], // Array of email attachments (max 40MB total per email)\n tags: [{ name: \"example string\" // Tag name (ASCII letters, numbers, underscores, dashes only, max 256 chars), value: \"example string\" // Tag value (ASCII letters, numbers, underscores, dashes only, max 256 chars) }], // Array of email tags for tracking and analytics\n headers: { \"example_key\": \"example string\" } // record/object with string keys, // Custom email headers (e.g., X-Custom-Header)\n});\n\nconst result = await resend_send_email.action();\n// outputSchema for result.data when operation === 'send_email':\n// {\n// operation: \"send_email\" // Send an email via Resend,\n// success: boolean // Whether the email was sent successfully,\n// email_id: string | undefined // Resend email ID if successful,\n// error: string // Error message if email sending failed\n// }\n\n\n// Get Email Status example\nconst resend_get_email_status = new ResendBubble({\n operation: \"get_email_status\", // Get the status of a sent email\n email_id: \"example string\", // Resend email ID to check status for\n});\n\nconst result = await resend_get_email_status.action();\n// outputSchema for result.data when operation === 'get_email_status':\n// {\n// operation: \"get_email_status\" // Get the status of a sent email,\n// success: boolean // Whether the status request was successful,\n// status: string | undefined // Current status of the email,\n// created_at: string | undefined // Timestamp when the email was created,\n// last_event: string | undefined // Last event that occurred with the email,\n// error: string // Error message if status request failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`resend failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
69
|
+
"requiredCredentials": [
|
|
70
|
+
"RESEND_CRED"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "http",
|
|
75
|
+
"alias": "fetch",
|
|
76
|
+
"type": "service",
|
|
77
|
+
"shortDescription": "Makes HTTP requests to external APIs and services",
|
|
78
|
+
"useCase": "- Calling external REST APIs",
|
|
79
|
+
"inputSchema": "{\n url: string // The URL to make the HTTP request to,\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" | \"HEAD\" | \"OPTIONS\" // HTTP method to use (default: GET),\n headers: Record<string, string> | undefined // HTTP headers to include in the request,\n body: unknown | undefined // Request body (string or JSON object),\n timeout: number // Request timeout in milliseconds (default: 30000, max: 120000),\n followRedirects: boolean // Whether to follow HTTP redirects (default: true),\n credentials: Record<string, string> | undefined // Optional credentials for authentication (injected at runtime)\n}",
|
|
80
|
+
"outputSchema": "{\n status: number // HTTP status code,\n statusText: string // HTTP status text,\n headers: Record<string, string> // Response headers,\n body: string // Response body as string,\n json: unknown | undefined // Parsed JSON response (if applicable),\n success: boolean // Whether the request was successful (HTTP 2xx status codes),\n error: string // Error message if request failed,\n responseTime: number // Response time in milliseconds,\n size: number // Response size in bytes\n}",
|
|
81
|
+
"usageExample": "// Example usage of http bubble\nconst http = new HttpBubble({\n url: \"example string\", // The URL to make the HTTP request to,\n method: \"GET\" // options: \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\", // HTTP method to use (default: GET),\n headers: { \"example_key\": \"example string\" } // record/object with string keys, // HTTP headers to include in the request,\n timeout: 30000 // default, // Request timeout in milliseconds (default: 30000, max: 120000),\n followRedirects: true // default, // Whether to follow HTTP redirects (default: true),\n});\n\nconst result = await http.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// status: number // HTTP status code,\n// statusText: string // HTTP status text,\n// headers: Record<string, string> // Response headers,\n// body: string // Response body as string,\n// json: unknown | undefined // Parsed JSON response (if applicable),\n// success: boolean // Whether the request was successful (HTTP 2xx status codes),\n// error: string // Error message if request failed,\n// responseTime: number // Response time in milliseconds,\n// size: number // Response size in bytes\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
82
|
+
"requiredCredentials": []
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "storage",
|
|
86
|
+
"alias": "r2",
|
|
87
|
+
"type": "service",
|
|
88
|
+
"shortDescription": "Cloudflare R2 storage operations for file management",
|
|
89
|
+
"useCase": "- Generate presigned upload URLs for client-side file uploads",
|
|
90
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
91
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
92
|
+
"usageExample": "// GetUploadUrl example\nconst storage_getUploadUrl = new StorageBubble({\n operation: \"getUploadUrl\", // Generate presigned upload URL\n bucketName: \"example string\", // Name of the R2 bucket\n fileName: \"example string\", // Original filename for the upload\n accountId: \"example string\", // Cloudflare Account ID - can be provided via credentials\n region: \"auto\" // default, // AWS region for R2 storage (defaults to auto)\n expirationMinutes: 60 // default, // URL expiration time in minutes\n contentType: \"example string\", // Content type for uploads\n userId: \"example string\", // User ID for secure file isolation\n});\n\nconst result = await storage_getUploadUrl.action();\n// outputSchema for result.data when operation === 'getUploadUrl':\n// {\n// operation: \"getUploadUrl\" // Generate presigned upload URL,\n// success: boolean // Whether the operation was successful,\n// uploadUrl: string | undefined // Presigned upload URL,\n// fileName: string | undefined // Secure filename generated for the upload,\n// contentType: string | undefined // Content type of the file,\n// error: string // Error message if operation failed\n// }\n\n\n// GetFile example\nconst storage_getFile = new StorageBubble({\n operation: \"getFile\", // Generate presigned download URL\n bucketName: \"example string\", // Name of the R2 bucket\n fileName: \"example string\", // Name of the file to retrieve\n accountId: \"example string\", // Cloudflare Account ID - can be provided via credentials\n region: \"auto\" // default, // AWS region for R2 storage (defaults to auto)\n expirationMinutes: 60 // default, // URL expiration time in minutes\n userId: \"example string\", // User ID for secure file isolation\n});\n\nconst result = await storage_getFile.action();\n// outputSchema for result.data when operation === 'getFile':\n// {\n// operation: \"getFile\" // Generate presigned download URL,\n// success: boolean // Whether the operation was successful,\n// downloadUrl: string | undefined // Presigned download URL,\n// fileUrl: string | undefined // Direct file access URL,\n// fileName: string | undefined // Name of the file,\n// fileSize: number | undefined // File size in bytes,\n// contentType: string | undefined // Content type of the file,\n// lastModified: string | undefined // Last modified timestamp in ISO format,\n// error: string // Error message if operation failed\n// }\n\n\n// DeleteFile example\nconst storage_deleteFile = new StorageBubble({\n operation: \"deleteFile\", // Delete file from bucket\n bucketName: \"example string\", // Name of the R2 bucket\n fileName: \"example string\", // Name of the file to delete\n accountId: \"example string\", // Cloudflare Account ID - can be provided via credentials\n region: \"auto\" // default, // AWS region for R2 storage (defaults to auto)\n});\n\nconst result = await storage_deleteFile.action();\n// outputSchema for result.data when operation === 'deleteFile':\n// {\n// operation: \"deleteFile\" // Delete file from bucket,\n// success: boolean // Whether the operation was successful,\n// fileName: string | undefined // Name of the deleted file,\n// deleted: boolean | undefined // Whether the file was successfully deleted,\n// error: string // Error message if operation failed\n// }\n\n\n// UpdateFile example\nconst storage_updateFile = new StorageBubble({\n operation: \"updateFile\", // Update/replace file content\n bucketName: \"example string\", // Name of the R2 bucket\n fileName: \"example string\", // Name of the file to update\n accountId: \"example string\", // Cloudflare Account ID - can be provided via credentials\n region: \"auto\" // default, // AWS region for R2 storage (defaults to auto)\n contentType: \"example string\", // Content type for uploads\n fileContent: \"example string\", // Base64 encoded file content or raw text content\n});\n\nconst result = await storage_updateFile.action();\n// outputSchema for result.data when operation === 'updateFile':\n// {\n// operation: \"updateFile\" // Update/replace file content,\n// success: boolean // Whether the operation was successful,\n// fileName: string | undefined // Name of the updated file,\n// updated: boolean | undefined // Whether the file was successfully updated,\n// contentType: string | undefined // Content type of the updated file,\n// error: string // Error message if operation failed\n// }\n\n\n// GetMultipleUploadUrls example\nconst storage_getMultipleUploadUrls = new StorageBubble({\n operation: \"getMultipleUploadUrls\", // Generate multiple presigned upload URLs for PDF + page images\n bucketName: \"example string\", // Name of the R2 bucket\n pdfFileName: \"example string\", // Original filename for the PDF\n pageCount: 42, // Number of pages to generate upload URLs for\n accountId: \"example string\", // Cloudflare Account ID - can be provided via credentials\n region: \"auto\" // default, // AWS region for R2 storage (defaults to auto)\n expirationMinutes: 60 // default, // URL expiration time in minutes\n userId: \"example string\", // User ID for secure file isolation\n});\n\nconst result = await storage_getMultipleUploadUrls.action();\n// outputSchema for result.data when operation === 'getMultipleUploadUrls':\n// {\n// operation: \"getMultipleUploadUrls\" // Generate multiple presigned upload URLs for PDF + page images,\n// success: boolean // Whether the operation was successful,\n// pdfUploadUrl: string | undefined // Presigned upload URL for PDF,\n// pdfFileName: string | undefined // Secure filename for PDF,\n// pageUploadUrls: { pageNumber: number, uploadUrl: string, fileName: string }[] | undefined // Array of upload URLs for page images,\n// error: string // Error message if operation failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`storage failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
93
|
+
"requiredCredentials": [
|
|
94
|
+
"CLOUDFLARE_R2_ACCESS_KEY",
|
|
95
|
+
"CLOUDFLARE_R2_SECRET_KEY",
|
|
96
|
+
"CLOUDFLARE_R2_ACCOUNT_ID"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "google-drive",
|
|
101
|
+
"alias": "gdrive",
|
|
102
|
+
"type": "service",
|
|
103
|
+
"shortDescription": "Google Drive integration for file management",
|
|
104
|
+
"useCase": "- Upload files and documents to Google Drive",
|
|
105
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
106
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
107
|
+
"usageExample": "// Upload File example\nconst googleDrive_upload_file = new GoogleDriveBubble({\n operation: \"upload_file\", // Upload a file to Google Drive\n name: \"example string\", // Name for the uploaded file\n content: \"example string\", // File content as base64 encoded string or plain text\n mimeType: \"example string\", // MIME type of the file (auto-detected if not provided)\n parent_folder_id: \"example string\", // ID of the parent folder (uploads to root if not provided)\n convert_to_google_docs: false // default, // Convert uploaded file to Google Docs format if possible\n});\n\nconst result = await googleDrive_upload_file.action();\n// outputSchema for result.data when operation === 'upload_file':\n// {\n// operation: \"upload_file\" // Upload a file to Google Drive,\n// success: boolean // Whether the file was uploaded successfully,\n// file: { id: string, name: string, mimeType: string, size: string | undefined, createdTime: string | undefined, modifiedTime: string | undefined, webViewLink: string | undefined, webContentLink: string | undefined, parents: string[] | undefined, shared: boolean | undefined, owners: { displayName: string | undefined, emailAddress: string | undefined }[] | undefined } | undefined // Uploaded file metadata,\n// error: string // Error message if operation failed\n// }\n\n\n// Download File example\nconst googleDrive_download_file = new GoogleDriveBubble({\n operation: \"download_file\", // Download a file from Google Drive\n file_id: \"example string\", // Google Drive file ID to download\n export_format: \"example string\", // Export format for Google Workspace files (e.g., \"application/pdf\", \"text/plain\")\n});\n\nconst result = await googleDrive_download_file.action();\n// outputSchema for result.data when operation === 'download_file':\n// {\n// operation: \"download_file\" // Download a file from Google Drive,\n// success: boolean // Whether the file was downloaded successfully,\n// content: string | undefined // File content as base64 encoded string,\n// filename: string | undefined // Original filename,\n// mimeType: string | undefined // MIME type of the downloaded file,\n// error: string // Error message if operation failed\n// }\n\n\n// List Files example\nconst googleDrive_list_files = new GoogleDriveBubble({\n operation: \"list_files\", // List files and folders in Google Drive\n folder_id: \"example string\", // ID of folder to list files from (lists from root if not provided)\n query: \"example string\", // Search query to filter files (e.g., \"name contains 'report'\"\n max_results: 100 // default, // Maximum number of files to return\n include_folders: true // default, // Include folders in the results\n order_by: \"modifiedTime desc\" // default, // Order results by field (e.g., \"name\", \"modifiedTime desc\")\n});\n\nconst result = await googleDrive_list_files.action();\n// outputSchema for result.data when operation === 'list_files':\n// {\n// operation: \"list_files\" // List files and folders in Google Drive,\n// success: boolean // Whether the file list was retrieved successfully,\n// files: { id: string, name: string, mimeType: string, size: string | undefined, createdTime: string | undefined, modifiedTime: string | undefined, webViewLink: string | undefined, webContentLink: string | undefined, parents: string[] | undefined, shared: boolean | undefined, owners: { displayName: string | undefined, emailAddress: string | undefined }[] | undefined }[] | undefined // List of files and folders,\n// total_count: number | undefined // Total number of files found,\n// next_page_token: string | undefined // Token for fetching next page of results,\n// error: string // Error message if operation failed\n// }\n\n\n// Create Folder example\nconst googleDrive_create_folder = new GoogleDriveBubble({\n operation: \"create_folder\", // Create a new folder in Google Drive\n name: \"example string\", // Name of the folder to create\n parent_folder_id: \"example string\", // ID of the parent folder (creates in root if not provided)\n});\n\nconst result = await googleDrive_create_folder.action();\n// outputSchema for result.data when operation === 'create_folder':\n// {\n// operation: \"create_folder\" // Create a new folder in Google Drive,\n// success: boolean // Whether the folder was created successfully,\n// folder: { id: string, name: string, webViewLink: string | undefined, parents: string[] | undefined } | undefined // Created folder metadata,\n// error: string // Error message if operation failed\n// }\n\n\n// Delete File example\nconst googleDrive_delete_file = new GoogleDriveBubble({\n operation: \"delete_file\", // Delete a file or folder from Google Drive\n file_id: \"example string\", // Google Drive file or folder ID to delete\n permanent: false // default, // Permanently delete (true) or move to trash (false)\n});\n\nconst result = await googleDrive_delete_file.action();\n// outputSchema for result.data when operation === 'delete_file':\n// {\n// operation: \"delete_file\" // Delete a file or folder from Google Drive,\n// success: boolean // Whether the file was deleted successfully,\n// deleted_file_id: string | undefined // ID of the deleted file,\n// error: string // Error message if operation failed\n// }\n\n\n// Get File Info example\nconst googleDrive_get_file_info = new GoogleDriveBubble({\n operation: \"get_file_info\", // Get detailed information about a file or folder\n file_id: \"example string\", // Google Drive file or folder ID to get info for\n include_permissions: false // default, // Include file permissions in the response\n});\n\nconst result = await googleDrive_get_file_info.action();\n// outputSchema for result.data when operation === 'get_file_info':\n// {\n// operation: \"get_file_info\" // Get detailed information about a file or folder,\n// success: boolean // Whether the file information was retrieved successfully,\n// file: { id: string, name: string, mimeType: string, size: string | undefined, createdTime: string | undefined, modifiedTime: string | undefined, webViewLink: string | undefined, webContentLink: string | undefined, parents: string[] | undefined, shared: boolean | undefined, owners: { displayName: string | undefined, emailAddress: string | undefined }[] | undefined } | undefined // File metadata and information,\n// permissions: { id: string, type: string, role: string, emailAddress: string | undefined, displayName: string | undefined }[] | undefined // File permissions (if requested),\n// error: string // Error message if operation failed\n// }\n\n\n// Share File example\nconst googleDrive_share_file = new GoogleDriveBubble({\n operation: \"share_file\", // Share a file or folder with specific users or make it public\n file_id: \"example string\", // Google Drive file or folder ID to share\n email_address: \"example string\", // Email address to share with (for specific user sharing)\n role: \"reader\" // options: \"reader\", \"writer\", \"commenter\", \"owner\", // Permission role to grant\n type: \"user\" // options: \"user\", \"group\", \"domain\", \"anyone\", // Type of permission to create\n send_notification: true // default, // Send notification email to the user\n});\n\nconst result = await googleDrive_share_file.action();\n// outputSchema for result.data when operation === 'share_file':\n// {\n// operation: \"share_file\" // Share a file or folder with specific users or make it public,\n// success: boolean // Whether the file was shared successfully,\n// permission_id: string | undefined // ID of the created permission,\n// share_link: string | undefined // Shareable link to the file,\n// error: string // Error message if operation failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`google-drive failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
108
|
+
"requiredCredentials": [
|
|
109
|
+
"GOOGLE_DRIVE_CRED"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "gmail",
|
|
114
|
+
"alias": "gmail",
|
|
115
|
+
"type": "service",
|
|
116
|
+
"shortDescription": "Gmail integration for email management",
|
|
117
|
+
"useCase": "- Send and receive emails with rich formatting",
|
|
118
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
119
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
120
|
+
"usageExample": "// Send Email example\nconst gmail_send_email = new GmailBubble({\n operation: \"send_email\", // Send an email message\n to: [\"example string\"], // List of recipient email addresses\n cc: [\"example string\"], // List of CC recipient email addresses\n bcc: [\"example string\"], // List of BCC recipient email addresses\n subject: \"example string\", // Email subject line\n body_text: \"example string\", // Plain text email body\n body_html: \"example string\", // HTML email body\n reply_to: \"example string\", // Reply-to email address\n thread_id: \"example string\", // Thread ID to reply to (for threaded conversations)\n});\n\nconst result = await gmail_send_email.action();\n// outputSchema for result.data when operation === 'send_email':\n// {\n// operation: \"send_email\" // Send an email message,\n// success: boolean // Whether the email was sent successfully,\n// message_id: string | undefined // Sent message ID,\n// thread_id: string | undefined // Thread ID,\n// error: string // Error message if operation failed\n// }\n\n\n// List Emails example\nconst gmail_list_emails = new GmailBubble({\n operation: \"list_emails\", // List emails in the user mailbox\n query: \"example string\", // Gmail search query (e.g., \"from:user@example.com is:unread\")\n label_ids: [\"example string\"], // Filter by specific label IDs\n include_spam_trash: false // default, // Include messages from SPAM and TRASH\n max_results: 100 // default, // Maximum number of messages to return\n page_token: \"example string\", // Token for pagination to get next page\n});\n\nconst result = await gmail_list_emails.action();\n// outputSchema for result.data when operation === 'list_emails':\n// {\n// operation: \"list_emails\" // List emails in the user mailbox,\n// success: boolean // Whether the email list was retrieved successfully,\n// messages: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined }[] | undefined // List of email messages,\n// next_page_token: string | undefined // Token for fetching next page,\n// result_size_estimate: number | undefined // Estimated total number of results,\n// error: string // Error message if operation failed\n// }\n\n\n// Get Email example\nconst gmail_get_email = new GmailBubble({\n operation: \"get_email\", // Get a specific email message\n message_id: \"example string\", // Gmail message ID to retrieve\n format: \"minimal\" // options: \"minimal\", \"full\", \"raw\", \"metadata\", // Format to return the message in\n metadata_headers: [\"example string\"], // List of headers to include when format is metadata\n});\n\nconst result = await gmail_get_email.action();\n// outputSchema for result.data when operation === 'get_email':\n// {\n// operation: \"get_email\" // Get a specific email message,\n// success: boolean // Whether the email was retrieved successfully,\n// message: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined } | undefined // Email message details,\n// error: string // Error message if operation failed\n// }\n\n\n// Search Emails example\nconst gmail_search_emails = new GmailBubble({\n operation: \"search_emails\", // Search emails with query\n query: \"example string\", // Gmail search query string\n max_results: 50 // default, // Maximum number of results to return\n include_spam_trash: false // default, // Include messages from SPAM and TRASH\n});\n\nconst result = await gmail_search_emails.action();\n// outputSchema for result.data when operation === 'search_emails':\n// {\n// operation: \"search_emails\" // Search emails with query,\n// success: boolean // Whether the email search was completed successfully,\n// messages: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined }[] | undefined // List of matching email messages,\n// result_size_estimate: number | undefined // Estimated total number of results,\n// error: string // Error message if operation failed\n// }\n\n\n// Mark As Read example\nconst gmail_mark_as_read = new GmailBubble({\n operation: \"mark_as_read\", // Mark one or more messages as read\n message_ids: [\"example string\"], // List of message IDs to mark as read\n});\n\nconst result = await gmail_mark_as_read.action();\n// outputSchema for result.data when operation === 'mark_as_read':\n// {\n// operation: \"mark_as_read\" // Mark one or more messages as read,\n// success: boolean // Whether the messages were marked as read successfully,\n// modified_messages: string[] | undefined // IDs of messages that were modified,\n// error: string // Error message if operation failed\n// }\n\n\n// Mark As Unread example\nconst gmail_mark_as_unread = new GmailBubble({\n operation: \"mark_as_unread\", // Mark one or more messages as unread\n message_ids: [\"example string\"], // List of message IDs to mark as unread\n});\n\nconst result = await gmail_mark_as_unread.action();\n// outputSchema for result.data when operation === 'mark_as_unread':\n// {\n// operation: \"mark_as_unread\" // Mark one or more messages as unread,\n// success: boolean // Whether the messages were marked as unread successfully,\n// modified_messages: string[] | undefined // IDs of messages that were modified,\n// error: string // Error message if operation failed\n// }\n\n\n// Create Draft example\nconst gmail_create_draft = new GmailBubble({\n operation: \"create_draft\", // Create a draft email\n to: [\"example string\"], // List of recipient email addresses\n cc: [\"example string\"], // List of CC recipient email addresses\n bcc: [\"example string\"], // List of BCC recipient email addresses\n subject: \"example string\", // Email subject line\n body_text: \"example string\", // Plain text email body\n body_html: \"example string\", // HTML email body\n reply_to: \"example string\", // Reply-to email address\n thread_id: \"example string\", // Thread ID to reply to (for threaded conversations)\n});\n\nconst result = await gmail_create_draft.action();\n// outputSchema for result.data when operation === 'create_draft':\n// {\n// operation: \"create_draft\" // Create a draft email,\n// success: boolean // Whether the draft was created successfully,\n// draft: { id: string, message: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined } } | undefined // Created draft,\n// error: string // Error message if operation failed\n// }\n\n\n// Send Draft example\nconst gmail_send_draft = new GmailBubble({\n operation: \"send_draft\", // Send a draft email\n draft_id: \"example string\", // Gmail draft ID to send\n});\n\nconst result = await gmail_send_draft.action();\n// outputSchema for result.data when operation === 'send_draft':\n// {\n// operation: \"send_draft\" // Send a draft email,\n// success: boolean // Whether the draft was sent successfully,\n// message_id: string | undefined // Sent message ID,\n// thread_id: string | undefined // Thread ID,\n// error: string // Error message if operation failed\n// }\n\n\n// List Drafts example\nconst gmail_list_drafts = new GmailBubble({\n operation: \"list_drafts\", // List draft emails\n query: \"example string\", // Search query to filter drafts\n max_results: 100 // default, // Maximum number of drafts to return\n page_token: \"example string\", // Token for pagination to get next page\n include_spam_trash: false // default, // Include drafts from SPAM and TRASH\n});\n\nconst result = await gmail_list_drafts.action();\n// outputSchema for result.data when operation === 'list_drafts':\n// {\n// operation: \"list_drafts\" // List draft emails,\n// success: boolean // Whether the draft list was retrieved successfully,\n// drafts: { id: string, message: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined } }[] | undefined // List of drafts,\n// next_page_token: string | undefined // Token for fetching next page,\n// result_size_estimate: number | undefined // Estimated total number of results,\n// error: string // Error message if operation failed\n// }\n\n\n// Delete Email example\nconst gmail_delete_email = new GmailBubble({\n operation: \"delete_email\", // Delete an email message permanently\n message_id: \"example string\", // Gmail message ID to delete\n});\n\nconst result = await gmail_delete_email.action();\n// outputSchema for result.data when operation === 'delete_email':\n// {\n// operation: \"delete_email\" // Delete an email message permanently,\n// success: boolean // Whether the email was deleted successfully,\n// deleted_message_id: string | undefined // ID of the deleted message,\n// error: string // Error message if operation failed\n// }\n\n\n// Trash Email example\nconst gmail_trash_email = new GmailBubble({\n operation: \"trash_email\", // Move an email message to trash\n message_id: \"example string\", // Gmail message ID to move to trash\n});\n\nconst result = await gmail_trash_email.action();\n// outputSchema for result.data when operation === 'trash_email':\n// {\n// operation: \"trash_email\" // Move an email message to trash,\n// success: boolean // Whether the email was moved to trash successfully,\n// trashed_message_id: string | undefined // ID of the trashed message,\n// error: string // Error message if operation failed\n// }\n\n\n// List Threads example\nconst gmail_list_threads = new GmailBubble({\n operation: \"list_threads\", // List email threads\n query: \"example string\", // Gmail search query to filter threads\n label_ids: [\"example string\"], // Filter by specific label IDs\n include_spam_trash: false // default, // Include threads from SPAM and TRASH\n max_results: 100 // default, // Maximum number of threads to return\n page_token: \"example string\", // Token for pagination to get next page\n});\n\nconst result = await gmail_list_threads.action();\n// outputSchema for result.data when operation === 'list_threads':\n// {\n// operation: \"list_threads\" // List email threads,\n// success: boolean // Whether the thread list was retrieved successfully,\n// threads: { id: string, historyId: string | undefined, messages: { id: string, threadId: string, labelIds: string[] | undefined, snippet: string | undefined, historyId: string | undefined, internalDate: string | undefined, sizeEstimate: number | undefined, raw: string | undefined, payload: { mimeType: string | undefined, headers: { name: string, value: string }[] | undefined, body: { data: string | undefined, size: number | undefined, attachmentId: string | undefined } | undefined, parts: unknown[] | undefined } | undefined }[] | undefined, snippet: string | undefined }[] | undefined // List of email threads,\n// next_page_token: string | undefined // Token for fetching next page,\n// result_size_estimate: number | undefined // Estimated total number of results,\n// error: string // Error message if operation failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`gmail failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
121
|
+
"requiredCredentials": [
|
|
122
|
+
"GMAIL_CRED"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"name": "google-sheets",
|
|
127
|
+
"alias": "sheets",
|
|
128
|
+
"type": "service",
|
|
129
|
+
"shortDescription": "Google Sheets integration for spreadsheet operations",
|
|
130
|
+
"useCase": "- Read and write spreadsheet data with flexible ranges",
|
|
131
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
132
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
133
|
+
"usageExample": "// Read Values example\nconst googleSheets_read_values = new GoogleSheetsBubble({\n operation: \"read_values\", // Read values from a range\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n range: \"example string\", // A1 notation range (e.g., \"Sheet1!A1:B10\")\n major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\", // Major dimension for the values\n value_render_option: \"FORMATTED_VALUE\" // options: \"FORMATTED_VALUE\", \"UNFORMATTED_VALUE\", \"FORMULA\", // How values should be represented in the output\n date_time_render_option: \"SERIAL_NUMBER\" // options: \"SERIAL_NUMBER\", \"FORMATTED_STRING\", // How date/time values should be rendered\n});\n\nconst result = await googleSheets_read_values.action();\n// outputSchema for result.data when operation === 'read_values':\n// {\n// operation: \"read_values\" // Read values from a range,\n// success: boolean // Whether the operation was successful,\n// range: string | undefined // The range that was read,\n// values: unknown[][] | undefined // The values that were read,\n// major_dimension: string | undefined // Major dimension of the returned values,\n// error: string // Error message if operation failed\n// }\n\n\n// Write Values example\nconst googleSheets_write_values = new GoogleSheetsBubble({\n operation: \"write_values\", // Write values to a range\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n range: \"example string\", // A1 notation range (e.g., \"Sheet1!A1:B10\")\n values: [[]], // Data to write as array of arrays\n major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\", // Major dimension for the values\n value_input_option: \"RAW\" // options: \"RAW\", \"USER_ENTERED\", // How input data should be interpreted\n include_values_in_response: false // default, // Include updated values in response\n});\n\nconst result = await googleSheets_write_values.action();\n// outputSchema for result.data when operation === 'write_values':\n// {\n// operation: \"write_values\" // Write values to a range,\n// success: boolean // Whether the operation was successful,\n// updated_range: string | undefined // The range that was updated,\n// updated_rows: number | undefined // Number of rows updated,\n// updated_columns: number | undefined // Number of columns updated,\n// updated_cells: number | undefined // Number of cells updated,\n// updated_data: { range: string, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined, values: unknown[][] } | undefined // Updated data if requested,\n// error: string // Error message if operation failed\n// }\n\n\n// Update Values example\nconst googleSheets_update_values = new GoogleSheetsBubble({\n operation: \"update_values\", // Update values in a specific range\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n range: \"example string\", // A1 notation range (e.g., \"Sheet1!A1:B10\")\n values: [[]], // Data to update as array of arrays\n major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\", // Major dimension for the values\n value_input_option: \"RAW\" // options: \"RAW\", \"USER_ENTERED\", // How input data should be interpreted\n include_values_in_response: false // default, // Include updated values in response\n});\n\nconst result = await googleSheets_update_values.action();\n// outputSchema for result.data when operation === 'update_values':\n// {\n// operation: \"update_values\" // Update values in a specific range,\n// success: boolean // Whether the operation was successful,\n// updated_range: string | undefined // The range that was updated,\n// updated_rows: number | undefined // Number of rows updated,\n// updated_columns: number | undefined // Number of columns updated,\n// updated_cells: number | undefined // Number of cells updated,\n// updated_data: { range: string, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined, values: unknown[][] } | undefined // Updated data if requested,\n// error: string // Error message if operation failed\n// }\n\n\n// Append Values example\nconst googleSheets_append_values = new GoogleSheetsBubble({\n operation: \"append_values\", // Append values to the end of a table\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n range: \"example string\", // A1 notation range to search for table (e.g., \"Sheet1!A:A\")\n values: [[]], // Data to append as array of arrays\n major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\", // Major dimension for the values\n value_input_option: \"RAW\" // options: \"RAW\", \"USER_ENTERED\", // How input data should be interpreted\n insert_data_option: \"OVERWRITE\" // options: \"OVERWRITE\", \"INSERT_ROWS\", // How data should be inserted\n include_values_in_response: false // default, // Include appended values in response\n});\n\nconst result = await googleSheets_append_values.action();\n// outputSchema for result.data when operation === 'append_values':\n// {\n// operation: \"append_values\" // Append values to the end of a table,\n// success: boolean // Whether the operation was successful,\n// table_range: string | undefined // The table range values were appended to,\n// updated_range: string | undefined // The range that was updated,\n// updated_rows: number | undefined // Number of rows updated,\n// updated_columns: number | undefined // Number of columns updated,\n// updated_cells: number | undefined // Number of cells updated,\n// error: string // Error message if operation failed\n// }\n\n\n// Clear Values example\nconst googleSheets_clear_values = new GoogleSheetsBubble({\n operation: \"clear_values\", // Clear values from a range\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n range: \"example string\", // A1 notation range (e.g., \"Sheet1!A1:B10\")\n});\n\nconst result = await googleSheets_clear_values.action();\n// outputSchema for result.data when operation === 'clear_values':\n// {\n// operation: \"clear_values\" // Clear values from a range,\n// success: boolean // Whether the operation was successful,\n// cleared_range: string | undefined // The range that was cleared,\n// error: string // Error message if operation failed\n// }\n\n\n// Batch Read Values example\nconst googleSheets_batch_read_values = new GoogleSheetsBubble({\n operation: \"batch_read_values\", // Read multiple ranges at once\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n ranges: [\"example string\"], // Array of A1 notation ranges\n major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\", // Major dimension for the values\n value_render_option: \"FORMATTED_VALUE\" // options: \"FORMATTED_VALUE\", \"UNFORMATTED_VALUE\", \"FORMULA\", // How values should be represented in the output\n date_time_render_option: \"SERIAL_NUMBER\" // options: \"SERIAL_NUMBER\", \"FORMATTED_STRING\", // How date/time values should be rendered\n});\n\nconst result = await googleSheets_batch_read_values.action();\n// outputSchema for result.data when operation === 'batch_read_values':\n// {\n// operation: \"batch_read_values\" // Read multiple ranges at once,\n// success: boolean // Whether the operation was successful,\n// value_ranges: { range: string, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined, values: unknown[][] }[] | undefined // Array of value ranges that were read,\n// error: string // Error message if operation failed\n// }\n\n\n// Batch Update Values example\nconst googleSheets_batch_update_values = new GoogleSheetsBubble({\n operation: \"batch_update_values\", // Update multiple ranges at once\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n value_ranges: [{ range: \"example string\" // A1 notation range, values: [[]] // Data values, major_dimension: \"ROWS\" // options: \"ROWS\", \"COLUMNS\" }], // Array of value ranges to update\n value_input_option: \"RAW\" // options: \"RAW\", \"USER_ENTERED\", // How input data should be interpreted\n include_values_in_response: false // default, // Include updated values in response\n});\n\nconst result = await googleSheets_batch_update_values.action();\n// outputSchema for result.data when operation === 'batch_update_values':\n// {\n// operation: \"batch_update_values\" // Update multiple ranges at once,\n// success: boolean // Whether the operation was successful,\n// total_updated_rows: number | undefined // Total number of rows updated across all ranges,\n// total_updated_columns: number | undefined // Total number of columns updated across all ranges,\n// total_updated_cells: number | undefined // Total number of cells updated across all ranges,\n// total_updated_sheets: number | undefined // Total number of sheets updated,\n// responses: { updated_range: string | undefined, updated_rows: number | undefined, updated_columns: number | undefined, updated_cells: number | undefined }[] | undefined // Individual update responses,\n// error: string // Error message if operation failed\n// }\n\n\n// Get Spreadsheet Info example\nconst googleSheets_get_spreadsheet_info = new GoogleSheetsBubble({\n operation: \"get_spreadsheet_info\", // Get spreadsheet metadata and properties\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n include_grid_data: false // default, // Include grid data in response\n});\n\nconst result = await googleSheets_get_spreadsheet_info.action();\n// outputSchema for result.data when operation === 'get_spreadsheet_info':\n// {\n// operation: \"get_spreadsheet_info\" // Get spreadsheet metadata and properties,\n// success: boolean // Whether the operation was successful,\n// spreadsheet: { spreadsheetId: string, properties: { title: string, locale: string | undefined, autoRecalc: string | undefined, timeZone: string | undefined } | undefined, sheets: { properties: { sheetId: number, title: string, index: number, sheetType: string | undefined, gridProperties: { rowCount: number | undefined, columnCount: number | undefined } | undefined } }[] | undefined, spreadsheetUrl: string | undefined } | undefined // Spreadsheet information,\n// error: string // Error message if operation failed\n// }\n\n\n// Create Spreadsheet example\nconst googleSheets_create_spreadsheet = new GoogleSheetsBubble({\n operation: \"create_spreadsheet\", // Create a new spreadsheet\n title: \"example string\", // Title for the new spreadsheet\n sheet_titles: [\"Sheet1\"] // default, // Titles for the initial sheets\n});\n\nconst result = await googleSheets_create_spreadsheet.action();\n// outputSchema for result.data when operation === 'create_spreadsheet':\n// {\n// operation: \"create_spreadsheet\" // Create a new spreadsheet,\n// success: boolean // Whether the operation was successful,\n// spreadsheet: { spreadsheetId: string, properties: { title: string, locale: string | undefined, autoRecalc: string | undefined, timeZone: string | undefined } | undefined, sheets: { properties: { sheetId: number, title: string, index: number, sheetType: string | undefined, gridProperties: { rowCount: number | undefined, columnCount: number | undefined } | undefined } }[] | undefined, spreadsheetUrl: string | undefined } | undefined // Created spreadsheet information,\n// error: string // Error message if operation failed\n// }\n\n\n// Add Sheet example\nconst googleSheets_add_sheet = new GoogleSheetsBubble({\n operation: \"add_sheet\", // Add a new sheet to spreadsheet\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n sheet_title: \"example string\", // Title for the new sheet\n row_count: 1000 // default, // Number of rows in the new sheet\n column_count: 26 // default, // Number of columns in the new sheet\n});\n\nconst result = await googleSheets_add_sheet.action();\n// outputSchema for result.data when operation === 'add_sheet':\n// {\n// operation: \"add_sheet\" // Add a new sheet to spreadsheet,\n// success: boolean // Whether the operation was successful,\n// sheet_id: number | undefined // ID of the added sheet,\n// sheet_title: string | undefined // Title of the added sheet,\n// error: string // Error message if operation failed\n// }\n\n\n// Delete Sheet example\nconst googleSheets_delete_sheet = new GoogleSheetsBubble({\n operation: \"delete_sheet\", // Delete a sheet from spreadsheet\n spreadsheet_id: \"example string\", // Google Sheets spreadsheet ID\n sheet_id: 42, // ID of the sheet to delete\n});\n\nconst result = await googleSheets_delete_sheet.action();\n// outputSchema for result.data when operation === 'delete_sheet':\n// {\n// operation: \"delete_sheet\" // Delete a sheet from spreadsheet,\n// success: boolean // Whether the operation was successful,\n// deleted_sheet_id: number | undefined // ID of the deleted sheet,\n// error: string // Error message if operation failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`google-sheets failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
134
|
+
"requiredCredentials": [
|
|
135
|
+
"GOOGLE_SHEETS_CRED"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "google-calendar",
|
|
140
|
+
"alias": "gcal",
|
|
141
|
+
"type": "service",
|
|
142
|
+
"shortDescription": "Google Calendar integration for managing events",
|
|
143
|
+
"useCase": "- List calendars and events with filters and pagination",
|
|
144
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
145
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
146
|
+
"usageExample": "// List Calendars example\nconst googleCalendar_list_calendars = new GoogleCalendarBubble({\n operation: \"list_calendars\", // List calendars for the user\n max_results: 50 // default, // Maximum number of calendars to return\n page_token: \"example string\", // Token for fetching next page\n});\n\nconst result = await googleCalendar_list_calendars.action();\n// outputSchema for result.data when operation === 'list_calendars':\n// {\n// operation: \"list_calendars\" // List calendars for the user,\n// success: boolean // Whether the calendar list was retrieved successfully,\n// calendars: { id: string, summary: string | undefined, description: string | undefined, timeZone: string | undefined, selected: boolean | undefined, accessRole: \"freeBusyReader\" | \"reader\" | \"writer\" | \"owner\" | undefined }[] | undefined // List of calendars,\n// next_page_token: string | undefined // Token for fetching next page,\n// error: string // Error message if operation failed\n// }\n\n\n// List Events example\nconst googleCalendar_list_events = new GoogleCalendarBubble({\n operation: \"list_events\", // List events in a calendar\n calendar_id: \"primary\" // default, // Calendar ID\n time_min: \"example string\", // Lower bound (RFC3339 timestamp)\n time_max: \"example string\", // Upper bound (RFC3339 timestamp)\n q: \"example string\", // Free text search query\n single_events: true // default, // Expand recurring events\n order_by: \"startTime\" // options: \"startTime\", \"updated\", // Sort order\n page_token: \"example string\", // Token for fetching next page\n max_results: 50 // default, // Maximum number of events to return\n});\n\nconst result = await googleCalendar_list_events.action();\n// outputSchema for result.data when operation === 'list_events':\n// {\n// operation: \"list_events\" // List events in a calendar,\n// success: boolean // Whether the event list was retrieved successfully,\n// events: { id: string, status: string | undefined, htmlLink: string | undefined, created: string | undefined, updated: string | undefined, summary: string | undefined, description: string | undefined, location: string | undefined, start: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, end: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, attendees: { email: string, optional: boolean | undefined, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined, displayName: string | undefined }[] | undefined, organizer: { email: string | undefined, displayName: string | undefined } | undefined, hangoutLink: string | undefined, conferenceData: unknown | undefined }[] | undefined // List of events,\n// next_page_token: string | undefined // Token for fetching next page,\n// error: string // Error message if operation failed\n// }\n\n\n// Get Event example\nconst googleCalendar_get_event = new GoogleCalendarBubble({\n operation: \"get_event\", // Get a single event\n calendar_id: \"primary\" // default, // Calendar ID\n event_id: \"example string\", // Event ID to retrieve\n});\n\nconst result = await googleCalendar_get_event.action();\n// outputSchema for result.data when operation === 'get_event':\n// {\n// operation: \"get_event\" // Get a single event,\n// success: boolean // Whether the event was retrieved successfully,\n// event: { id: string, status: string | undefined, htmlLink: string | undefined, created: string | undefined, updated: string | undefined, summary: string | undefined, description: string | undefined, location: string | undefined, start: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, end: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, attendees: { email: string, optional: boolean | undefined, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined, displayName: string | undefined }[] | undefined, organizer: { email: string | undefined, displayName: string | undefined } | undefined, hangoutLink: string | undefined, conferenceData: unknown | undefined } | undefined // Event details,\n// error: string // Error message if operation failed\n// }\n\n\n// Create Event example\nconst googleCalendar_create_event = new GoogleCalendarBubble({\n operation: \"create_event\", // Create an event\n calendar_id: \"primary\" // default, // Calendar ID\n summary: \"example string\", // Event title\n description: \"example string\", // Event description\n location: \"example string\", // Event location\n start: { dateTime: \"example string\" // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: \"example string\" // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: \"example string\" // Time zone for the event time }, // Start date/time\n end: { dateTime: \"example string\" // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: \"example string\" // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: \"example string\" // Time zone for the event time }, // End date/time\n attendees: [{ email: \"example string\" // Attendee email, optional: true // Whether this attendee is optional, responseStatus: \"needsAction\" // options: \"needsAction\", \"declined\", \"tentative\", \"accepted\" // Response status of the attendee, displayName: \"example string\" // Display name of the attendee }], // List of event attendees\n conference: false // default, // Create a Google Meet conference link\n});\n\nconst result = await googleCalendar_create_event.action();\n// outputSchema for result.data when operation === 'create_event':\n// {\n// operation: \"create_event\" // Create an event,\n// success: boolean // Whether the event was created successfully,\n// event: { id: string, status: string | undefined, htmlLink: string | undefined, created: string | undefined, updated: string | undefined, summary: string | undefined, description: string | undefined, location: string | undefined, start: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, end: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, attendees: { email: string, optional: boolean | undefined, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined, displayName: string | undefined }[] | undefined, organizer: { email: string | undefined, displayName: string | undefined } | undefined, hangoutLink: string | undefined, conferenceData: unknown | undefined } | undefined // Created event details,\n// error: string // Error message if operation failed\n// }\n\n\n// Update Event example\nconst googleCalendar_update_event = new GoogleCalendarBubble({\n operation: \"update_event\", // Update an existing event\n calendar_id: \"primary\" // default, // Calendar ID\n event_id: \"example string\", // Event ID to update\n summary: \"example string\", // Event title\n description: \"example string\", // Event description\n location: \"example string\", // Event location\n start: { dateTime: \"example string\" // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: \"example string\" // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: \"example string\" // Time zone for the event time }, // Start date/time\n end: { dateTime: \"example string\" // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: \"example string\" // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: \"example string\" // Time zone for the event time }, // End date/time\n attendees: [{ email: \"example string\" // Attendee email, optional: true // Whether this attendee is optional, responseStatus: \"needsAction\" // options: \"needsAction\", \"declined\", \"tentative\", \"accepted\" // Response status of the attendee, displayName: \"example string\" // Display name of the attendee }], // List of event attendees\n});\n\nconst result = await googleCalendar_update_event.action();\n// outputSchema for result.data when operation === 'update_event':\n// {\n// operation: \"update_event\" // Update an existing event,\n// success: boolean // Whether the event was updated successfully,\n// event: { id: string, status: string | undefined, htmlLink: string | undefined, created: string | undefined, updated: string | undefined, summary: string | undefined, description: string | undefined, location: string | undefined, start: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, end: { dateTime: string | undefined, date: string | undefined, timeZone: string | undefined } | undefined, attendees: { email: string, optional: boolean | undefined, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined, displayName: string | undefined }[] | undefined, organizer: { email: string | undefined, displayName: string | undefined } | undefined, hangoutLink: string | undefined, conferenceData: unknown | undefined } | undefined // Updated event details,\n// error: string // Error message if operation failed\n// }\n\n\n// Delete Event example\nconst googleCalendar_delete_event = new GoogleCalendarBubble({\n operation: \"delete_event\", // Delete an event\n calendar_id: \"primary\" // default, // Calendar ID\n event_id: \"example string\", // Event ID to delete\n send_updates: \"all\" // options: \"all\", \"externalOnly\", \"none\", // Whether to notify attendees\n});\n\nconst result = await googleCalendar_delete_event.action();\n// outputSchema for result.data when operation === 'delete_event':\n// {\n// operation: \"delete_event\" // Delete an event,\n// success: boolean // Whether the event was deleted successfully,\n// deleted: boolean | undefined // Whether the event was actually deleted,\n// error: string // Error message if operation failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`google-calendar failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
147
|
+
"requiredCredentials": [
|
|
148
|
+
"GOOGLE_CALENDAR_CRED"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "apify",
|
|
153
|
+
"alias": "scrape",
|
|
154
|
+
"type": "service",
|
|
155
|
+
"shortDescription": "Run any Apify actor for web scraping and automation",
|
|
156
|
+
"useCase": "- Social media scraping (Instagram, Reddit, LinkedIn, etc.)",
|
|
157
|
+
"inputSchema": "{\n actorId: string // The Apify actor to run. Examples: \"apify/instagram-scraper\", \"apify/reddit-scraper\", etc.,\n input: Record<string, unknown> // Input parameters for the actor. Structure depends on the specific actor being used.,\n waitForFinish: boolean | undefined // Whether to wait for the actor run to complete before returning,\n timeout: number | undefined // Maximum time to wait for actor completion in milliseconds (default: 120000),\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime)\n}",
|
|
158
|
+
"outputSchema": "{\n runId: string // Apify actor run ID,\n status: string // Actor run status (READY, RUNNING, SUCCEEDED, FAILED, etc.),\n datasetId: string | undefined // Dataset ID where results are stored,\n items: unknown[] | undefined // Array of scraped items (if waitForFinish is true). Structure depends on the actor.,\n itemsCount: number | undefined // Total number of items scraped,\n consoleUrl: string // URL to view the actor run in Apify console,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
159
|
+
"usageExample": "// Example usage of apify bubble\nconst apify = new ApifyBubble({\n actorId: \"example string\", // The Apify actor to run. Examples: \"apify/instagram-scraper\", \"apify/reddit-scraper\", etc.,\n input: {} // record/object with string keys, // Input parameters for the actor. Structure depends on the specific actor being used.,\n waitForFinish: true // default, // Whether to wait for the actor run to complete before returning,\n timeout: 120000 // default, // Maximum time to wait for actor completion in milliseconds (default: 120000),\n});\n\nconst result = await apify.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// runId: string // Apify actor run ID,\n// status: string // Actor run status (READY, RUNNING, SUCCEEDED, FAILED, etc.),\n// datasetId: string | undefined // Dataset ID where results are stored,\n// items: unknown[] | undefined // Array of scraped items (if waitForFinish is true). Structure depends on the actor.,\n// itemsCount: number | undefined // Total number of items scraped,\n// consoleUrl: string // URL to view the actor run in Apify console,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
160
|
+
"requiredCredentials": [
|
|
161
|
+
"APIFY_CRED"
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "bubbleflow-generator",
|
|
166
|
+
"alias": "generate-flow",
|
|
167
|
+
"type": "workflow",
|
|
168
|
+
"shortDescription": "Generate BubbleFlow code from natural language",
|
|
169
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
170
|
+
"inputSchema": "{\n prompt: string // Natural language description of the desired BubbleFlow,\n credentials: Record<string, string> | undefined // Credentials for AI agent operations\n}",
|
|
171
|
+
"outputSchema": "{\n generatedCode: string // The generated BubbleFlow TypeScript code,\n isValid: boolean // Whether the generated code is valid,\n success: boolean,\n error: string,\n toolCalls: unknown[] // The tool calls made by the AI agent,\n summary: string // High-level instructions for using the validated flow,\n inputsSchema: string // JSON Schema (string) representing the inputs of the flow\n}",
|
|
172
|
+
"usageExample": "// Example usage of bubbleflow-generator bubble\nconst bubbleflowGenerator = new BubbleflowGeneratorBubble({\n prompt: \"example string\", // Natural language description of the desired BubbleFlow,\n});\n\nconst result = await bubbleflowGenerator.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// generatedCode: string // The generated BubbleFlow TypeScript code,\n// isValid: boolean // Whether the generated code is valid,\n// success: boolean,\n// error: string,\n// toolCalls: unknown[] // The tool calls made by the AI agent,\n// summary: string // High-level instructions for using the validated flow,\n// inputsSchema: string // JSON Schema (string) representing the inputs of the flow\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
173
|
+
"requiredCredentials": [
|
|
174
|
+
"GOOGLE_GEMINI_CRED",
|
|
175
|
+
"OPENROUTER_CRED"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"name": "database-analyzer",
|
|
180
|
+
"alias": "analyze-db",
|
|
181
|
+
"type": "workflow",
|
|
182
|
+
"shortDescription": "Analyzes database schema structure and metadata",
|
|
183
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
184
|
+
"inputSchema": "{\n dataSourceType: \"postgresql\" // Data source type to analyze,\n ignoreSSLErrors: boolean // Ignore SSL certificate errors,\n includeMetadata: boolean // Include enum values and column constraints,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime),\n injectedMetadata: { tables: Record<string, Record<string, string>> | undefined, tableNotes: Record<string, string> | undefined, rules: string[] | undefined } | undefined // Additional database context injected from user credentials metadata\n}",
|
|
185
|
+
"outputSchema": "{\n success: boolean,\n error: string,\n databaseSchema: { rawData: Record<string, unknown>[] | undefined, cleanedJSON: string | undefined, tableCount: number | undefined, tableNames: string[] | undefined } | undefined,\n analysisSummary: { dataSourceType: string, connectionSuccessful: boolean, analysisTimestamp: unknown } | undefined\n}",
|
|
186
|
+
"usageExample": "// Example usage of database-analyzer bubble\nconst databaseAnalyzer = new DatabaseAnalyzerBubble({\n dataSourceType: \"postgresql\", // Data source type to analyze,\n ignoreSSLErrors: false // default, // Ignore SSL certificate errors,\n includeMetadata: true // default, // Include enum values and column constraints,\n injectedMetadata: { tables: { \"example_key\": { \"example_key\": \"example string\" } // record/object with string keys } // record/object with string keys, tableNotes: { \"example_key\": \"example string\" } // record/object with string keys, rules: [\"example string\"] }, // Additional database context injected from user credentials metadata,\n});\n\nconst result = await databaseAnalyzer.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// success: boolean,\n// error: string,\n// databaseSchema: { rawData: Record<string, unknown>[] | undefined, cleanedJSON: string | undefined, tableCount: number | undefined, tableNames: string[] | undefined } | undefined,\n// analysisSummary: { dataSourceType: string, connectionSuccessful: boolean, analysisTimestamp: unknown } | undefined\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
187
|
+
"requiredCredentials": [
|
|
188
|
+
"DATABASE_CRED"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "slack-notifier",
|
|
193
|
+
"alias": "notify-slack",
|
|
194
|
+
"type": "workflow",
|
|
195
|
+
"shortDescription": "Data analyst-powered Slack notifications that tell compelling stories",
|
|
196
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
197
|
+
"inputSchema": "{\n contentToFormat: string // Raw content or data to format for Slack,\n originalUserQuery: string | undefined // Original user question or context,\n targetChannel: string // Slack channel name (without #) or channel ID,\n messageTitle: string | undefined // Custom title for the Slack message,\n messageStyle: \"professional\" | \"casual\" | \"technical\" | \"concise\" | \"detailed\" // Style and tone for message formatting,\n includeFormatting: boolean // Include emojis and rich Slack formatting,\n maxMessageLength: number // Maximum message length for Slack,\n aiModel: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\", temperature: number, maxTokens: number } | undefined // AI model settings for content formatting,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime)\n}",
|
|
198
|
+
"outputSchema": "{\n success: boolean,\n error: string,\n messageInfo: { messageTimestamp: string | undefined, channelId: string | undefined, channelName: string | undefined, formattedMessage: string | undefined, messageLength: number | undefined } | undefined,\n formattingInfo: { modelUsed: string | undefined, wasTruncated: boolean, originalLength: number | undefined } | undefined\n}",
|
|
199
|
+
"usageExample": "// Example usage of slack-notifier bubble\nconst slackNotifier = new SlackNotifierBubble({\n contentToFormat: \"example string\", // Raw content or data to format for Slack,\n originalUserQuery: \"example string\", // Original user question or context,\n targetChannel: \"example string\", // Slack channel name (without #) or channel ID,\n messageTitle: \"example string\", // Custom title for the Slack message,\n messageStyle: \"professional\" // options: \"professional\", \"casual\", \"technical\", \"concise\", \"detailed\", // Style and tone for message formatting,\n includeFormatting: true // default, // Include emojis and rich Slack formatting,\n maxMessageLength: 3000 // default, // Maximum message length for Slack,\n aiModel: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\", temperature: 0.3 // default, maxTokens: 50000 // default }, // AI model settings for content formatting,\n});\n\nconst result = await slackNotifier.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// success: boolean,\n// error: string,\n// messageInfo: { messageTimestamp: string | undefined, channelId: string | undefined, channelName: string | undefined, formattedMessage: string | undefined, messageLength: number | undefined } | undefined,\n// formattingInfo: { modelUsed: string | undefined, wasTruncated: boolean, originalLength: number | undefined } | undefined\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
200
|
+
"requiredCredentials": [
|
|
201
|
+
"SLACK_CRED",
|
|
202
|
+
"OPENAI_CRED",
|
|
203
|
+
"GOOGLE_GEMINI_CRED",
|
|
204
|
+
"ANTHROPIC_CRED"
|
|
205
|
+
]
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "slack-data-assistant",
|
|
209
|
+
"alias": "slack-data-bot",
|
|
210
|
+
"type": "workflow",
|
|
211
|
+
"shortDescription": "AI-powered Slack bot that answers data questions by querying databases",
|
|
212
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
213
|
+
"inputSchema": "{\n slackChannel: string // Slack channel ID where the bot will respond,\n slackThreadTs: string | undefined // Thread timestamp if replying to a thread,\n userQuestion: string // The user question from Slack,\n userName: string | undefined // Name of the user asking the question,\n name: string // Name of the AI assistant (e.g., \"DataBot\", \"Analytics Assistant\"),\n dataSourceType: \"postgresql\" | \"mysql\" | \"sqlite\" | \"mariadb\" | \"mssql\" // Type of database to analyze,\n databaseUrl: string | undefined // Database connection URL (if not using credentials),\n ignoreSSLErrors: boolean // Ignore SSL certificate errors for database connection,\n aiModel: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" // AI model to use for query generation,\n temperature: number // Temperature for AI responses (lower = more focused),\n verbosity: \"1\" | \"2\" | \"3\" | \"4\" | \"5\" // Response verbosity level (1=concise, 5=comprehensive),\n technicality: \"1\" | \"2\" | \"3\" | \"4\" | \"5\" // Technical complexity level (1=plain English, 5=expert),\n includeQuery: boolean // Include the SQL query in the response,\n includeExplanation: boolean // Include query explanation in the response,\n injectedMetadata: { tables: Record<string, Record<string, string>> | undefined, tableNotes: Record<string, string> | undefined, rules: string[] | undefined } | undefined // Additional database context injected from user credentials metadata,\n additionalContext: string | undefined // Additional context about how to answer the question,\n maxQueries: number // Maximum number of queries to run,\n credentials: Record<string, string> | undefined // Credentials for various services\n}",
|
|
214
|
+
"outputSchema": "{\n success: boolean // Whether the workflow completed successfully,\n error: string // Error message if workflow failed,\n query: string | undefined // Generated SQL query,\n queryExplanation: string | undefined // Explanation of the query,\n queryResults: Record<string, unknown>[] | undefined // Results from the database query,\n formattedResponse: string | undefined // Formatted response for Slack,\n slackBlocks: unknown[] | undefined // Slack block kit formatted message,\n slackMessageTs: string | undefined // Timestamp of sent Slack message,\n isDataQuestion: boolean | undefined // Whether the question was data-related,\n metadata: { executionTime: number, rowCount: number | undefined, wordCount: number | undefined } | undefined\n}",
|
|
215
|
+
"usageExample": "// Example usage of slack-data-assistant bubble\nconst slackDataAssistant = new SlackDataAssistantBubble({\n slackChannel: \"example string\", // Slack channel ID where the bot will respond,\n slackThreadTs: \"example string\", // Thread timestamp if replying to a thread,\n userQuestion: \"example string\", // The user question from Slack,\n userName: \"example string\", // Name of the user asking the question,\n name: \"Data Assistant\" // default, // Name of the AI assistant (e.g., \"DataBot\", \"Analytics Assistant\"),\n dataSourceType: \"postgresql\" // options: \"postgresql\", \"mysql\", \"sqlite\", \"mariadb\", \"mssql\", // Type of database to analyze,\n databaseUrl: \"example string\", // Database connection URL (if not using credentials),\n ignoreSSLErrors: false // default, // Ignore SSL certificate errors for database connection,\n aiModel: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\", // AI model to use for query generation,\n temperature: 0.3 // default, // Temperature for AI responses (lower = more focused),\n verbosity: \"1\" // options: \"1\", \"2\", \"3\", \"4\", \"5\", // Response verbosity level (1=concise, 5=comprehensive),\n technicality: \"1\" // options: \"1\", \"2\", \"3\", \"4\", \"5\", // Technical complexity level (1=plain English, 5=expert),\n includeQuery: true // default, // Include the SQL query in the response,\n includeExplanation: true // default, // Include query explanation in the response,\n injectedMetadata: { tables: { \"example_key\": { \"example_key\": \"example string\" } // record/object with string keys } // record/object with string keys, tableNotes: { \"example_key\": \"example string\" } // record/object with string keys, rules: [\"example string\"] }, // Additional database context injected from user credentials metadata,\n additionalContext: \"example string\", // Additional context about how to answer the question,\n maxQueries: 20 // default, // Maximum number of queries to run,\n});\n\nconst result = await slackDataAssistant.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// success: boolean // Whether the workflow completed successfully,\n// error: string // Error message if workflow failed,\n// query: string | undefined // Generated SQL query,\n// queryExplanation: string | undefined // Explanation of the query,\n// queryResults: Record<string, unknown>[] | undefined // Results from the database query,\n// formattedResponse: string | undefined // Formatted response for Slack,\n// slackBlocks: unknown[] | undefined // Slack block kit formatted message,\n// slackMessageTs: string | undefined // Timestamp of sent Slack message,\n// isDataQuestion: boolean | undefined // Whether the question was data-related,\n// metadata: { executionTime: number, rowCount: number | undefined, wordCount: number | undefined } | undefined\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
216
|
+
"requiredCredentials": [
|
|
217
|
+
"DATABASE_CRED",
|
|
218
|
+
"SLACK_CRED",
|
|
219
|
+
"OPENAI_CRED",
|
|
220
|
+
"GOOGLE_GEMINI_CRED",
|
|
221
|
+
"ANTHROPIC_CRED"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "slack-formatter-agent",
|
|
226
|
+
"alias": "slack-format",
|
|
227
|
+
"type": "service",
|
|
228
|
+
"shortDescription": "AI agent for creating well-formatted Slack messages with adjustable verbosity and technicality",
|
|
229
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
230
|
+
"inputSchema": "{\n message: string // The message or question to send to the AI agent,\n verbosity: \"1\" | \"2\" | \"3\" | \"4\" | \"5\" // Response verbosity level (1-5): 1=concise bullet points, 5=comprehensive explanations,\n technicality: \"1\" | \"2\" | \"3\" | \"4\" | \"5\" // Technical complexity level (1-5): 1=plain English, 5=expert terminology,\n includeBlockKit: boolean // Include Slack Block Kit JSON for rich formatting,\n includeQuery: boolean // Include the query that was executed in the response,\n includeExplanation: boolean // Include explanation of what the query does and why it was chosen,\n model: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\", temperature: number, maxTokens: number | undefined } // AI model configuration including provider, temperature, and tokens,\n tools: { name: string, credentials: Record<string, string> | undefined, config: Record<string, unknown> | undefined }[] // Array of tool bubbles the AI agent can use,\n maxIterations: number // Maximum number of iterations for the agent workflow,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime),\n additionalContext: string | undefined // Additional context about how to answer the question\n}",
|
|
231
|
+
"outputSchema": "{\n response: string // The AI agents formatted response in Slack markdown,\n blocks: { type: \"section\" | \"header\" | \"divider\" | \"context\" | \"actions\" | \"input\" | \"file\" | \"image\", text: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined } | undefined, block_id: string | undefined, accessory: unknown | undefined, fields: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined }[] | undefined, element: unknown | undefined, label: unknown | undefined, hint: unknown | undefined, optional: boolean | undefined, alt_text: string | undefined, image_url: string | undefined, title: { type: \"plain_text\", text: string, emoji: boolean | undefined } | undefined, elements: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined }[] | undefined }[] | undefined // Slack Block Kit formatted blocks for rich message display,\n metadata: { verbosityLevel: string, technicalityLevel: string, wordCount: number, blockCount: number | undefined } // Metadata about the formatting,\n toolCalls: { tool: string, input: unknown, output: unknown }[] | undefined // Array of tool calls made during the conversation,\n iterations: number // Number of back-and-forth iterations in the agent workflow,\n error: string // Error message of the run, undefined if successful,\n success: boolean // Whether the agent execution completed successfully\n}",
|
|
232
|
+
"usageExample": "// Example usage of slack-formatter-agent bubble\nconst slackFormatterAgent = new SlackFormatterAgentBubble({\n message: \"example string\", // The message or question to send to the AI agent,\n verbosity: \"1\" // options: \"1\", \"2\", \"3\", \"4\", \"5\", // Response verbosity level (1-5): 1=concise bullet points, 5=comprehensive explanations,\n technicality: \"1\" // options: \"1\", \"2\", \"3\", \"4\", \"5\", // Technical complexity level (1-5): 1=plain English, 5=expert terminology,\n includeBlockKit: true // default, // Include Slack Block Kit JSON for rich formatting,\n includeQuery: false // default, // Include the query that was executed in the response,\n includeExplanation: false // default, // Include explanation of what the query does and why it was chosen,\n model: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use (format: provider/model-name), temperature: 0.7 // default // Temperature for response randomness (0 = deterministic, 2 = very random), maxTokens: 10000 // default // Maximum number of tokens to generate in response } // structure, // AI model configuration including provider, temperature, and tokens,\n tools: [{ name: \"example string\" // Name of the tool bubble to enable for the AI agent, credentials: { \"example_key\": \"example string\" } // record/object with string keys // structure // Credential types to use for the tool bubble (injected at runtime), config: {} // record/object with string keys // Configuration for the tool bubble }] // example for array, // Array of tool bubbles the AI agent can use,\n maxIterations: 10 // default, // Maximum number of iterations for the agent workflow,\n additionalContext: \"example string\", // Additional context about how to answer the question,\n});\n\nconst result = await slackFormatterAgent.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// response: string // The AI agents formatted response in Slack markdown,\n// blocks: { type: \"section\" | \"header\" | \"divider\" | \"context\" | \"actions\" | \"input\" | \"file\" | \"image\", text: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined } | undefined, block_id: string | undefined, accessory: unknown | undefined, fields: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined }[] | undefined, element: unknown | undefined, label: unknown | undefined, hint: unknown | undefined, optional: boolean | undefined, alt_text: string | undefined, image_url: string | undefined, title: { type: \"plain_text\", text: string, emoji: boolean | undefined } | undefined, elements: { type: \"plain_text\" | \"mrkdwn\", text: string, emoji: boolean | undefined, verbatim: boolean | undefined }[] | undefined }[] | undefined // Slack Block Kit formatted blocks for rich message display,\n// metadata: { verbosityLevel: string, technicalityLevel: string, wordCount: number, blockCount: number | undefined } // Metadata about the formatting,\n// toolCalls: { tool: string, input: unknown, output: unknown }[] | undefined // Array of tool calls made during the conversation,\n// iterations: number // Number of back-and-forth iterations in the agent workflow,\n// error: string // Error message of the run, undefined if successful,\n// success: boolean // Whether the agent execution completed successfully\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
233
|
+
"requiredCredentials": [
|
|
234
|
+
"OPENAI_CRED",
|
|
235
|
+
"GOOGLE_GEMINI_CRED",
|
|
236
|
+
"ANTHROPIC_CRED"
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"name": "pdf-form-operations",
|
|
241
|
+
"alias": "pdf-forms",
|
|
242
|
+
"type": "workflow",
|
|
243
|
+
"shortDescription": "PDF form field operations (discover, fill, analyze, validate, convert-to-images, convert-to-markdown)",
|
|
244
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
245
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
246
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
247
|
+
"usageExample": "// Discover example\nconst pdfFormOperations_discover = new PdfFormOperationsBubble({\n operation: \"discover\",\n pdfData: \"example string\", // Base64 encoded PDF data\n targetPage: 42, // Extract fields from specific page only (default: all pages)\n});\n\nconst result = await pdfFormOperations_discover.action();\n// outputSchema for result.data when operation === 'discover':\n// {\n// operation: \"discover\",\n// fields: { id: number, page: number, name: string, type: string, field_type: string, current_value: string, choices: string[], rect: unknown, x: number, y: number, width: number, height: number, field_flags: number, label: string, potential_labels: string[] }[],\n// totalFields: number,\n// success: boolean,\n// error: string\n// }\n\n\n// Fill example\nconst pdfFormOperations_fill = new PdfFormOperationsBubble({\n operation: \"fill\",\n pdfData: \"example string\", // Base64 encoded PDF data\n fieldValues: { \"example_key\": \"example string\" } // record/object with string keys, // Field name to value mapping\n});\n\nconst result = await pdfFormOperations_fill.action();\n// outputSchema for result.data when operation === 'fill':\n// {\n// operation: \"fill\",\n// filledPdfData: string // Base64 encoded filled PDF data,\n// filledFields: number,\n// verification: Record<string, { value: string, type: string, page: number }>,\n// success: boolean,\n// error: string\n// }\n\n\n// Analyze-checkboxes example\nconst pdfFormOperations_analyze_checkboxes = new PdfFormOperationsBubble({\n operation: \"analyze-checkboxes\",\n pdfData: \"example string\", // Base64 encoded PDF data\n});\n\nconst result = await pdfFormOperations_analyze_checkboxes.action();\n// outputSchema for result.data when operation === 'analyze-checkboxes':\n// {\n// operation: \"analyze-checkboxes\",\n// checkboxes: Record<string, { page: number, current_value: string, possible_values: string[], field_flags: number }>,\n// totalCheckboxes: number,\n// success: boolean,\n// error: string\n// }\n\n\n// Validate example\nconst pdfFormOperations_validate = new PdfFormOperationsBubble({\n operation: \"validate\",\n pdfData: \"example string\", // Base64 encoded PDF data\n});\n\nconst result = await pdfFormOperations_validate.action();\n// outputSchema for result.data when operation === 'validate':\n// {\n// operation: \"validate\",\n// fields: Record<string, { value: string, type: string, page: number }>,\n// totalFields: number,\n// filledFields: number,\n// emptyFields: number,\n// success: boolean,\n// error: string\n// }\n\n\n// Convert-to-images example\nconst pdfFormOperations_convert_to_images = new PdfFormOperationsBubble({\n operation: \"convert-to-images\",\n pdfData: \"example string\", // Base64 encoded PDF data\n format: \"png\" // options: \"png\", \"jpeg\", // Output image format\n quality: 0.8 // default, // JPEG quality (0.1-1.0, only for JPEG format)\n dpi: 150 // default, // Output DPI (dots per inch)\n pages: [42], // Specific page numbers to convert (1-indexed). If not provided, converts all pages\n});\n\nconst result = await pdfFormOperations_convert_to_images.action();\n// outputSchema for result.data when operation === 'convert-to-images':\n// {\n// operation: \"convert-to-images\",\n// images: { pageNumber: number, imageData: string, format: string, width: number, height: number }[],\n// totalPages: number,\n// convertedPages: number,\n// success: boolean,\n// error: string\n// }\n\n\n// Convert-to-markdown example\nconst pdfFormOperations_convert_to_markdown = new PdfFormOperationsBubble({\n operation: \"convert-to-markdown\",\n pdfData: \"example string\", // Base64 encoded PDF data\n pages: [42], // Specific page numbers to convert (1-indexed). If not provided, converts all pages\n includeFormFields: true // default, // Whether to include form field information in the markdown\n});\n\nconst result = await pdfFormOperations_convert_to_markdown.action();\n// outputSchema for result.data when operation === 'convert-to-markdown':\n// {\n// operation: \"convert-to-markdown\",\n// markdown: string // Markdown representation of the PDF content,\n// pages: { pageNumber: number, markdown: string, formFields: { id: number, name: string, type: string, value: string, x: number, y: number }[] | undefined }[],\n// totalPages: number,\n// convertedPages: number,\n// success: boolean,\n// error: string\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`pdf-form-operations failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
248
|
+
"requiredCredentials": []
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"name": "pdf-ocr-workflow",
|
|
252
|
+
"alias": "pdf-ocr",
|
|
253
|
+
"type": "workflow",
|
|
254
|
+
"shortDescription": "PDF OCR workflow: identify fields or autofill forms using AI analysis",
|
|
255
|
+
"useCase": "- **Identify**: Form schema generation, document structure analysis",
|
|
256
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
257
|
+
"outputSchema": "Complex schema - see usage example for structure",
|
|
258
|
+
"usageExample": "// Identify example\nconst pdfOcrWorkflow_identify = new PdfOcrWorkflowBubble({\n mode: \"identify\", // Identify form fields and generate descriptive names\n pdfData: \"example string\", // Base64 encoded PDF data\n discoveryOptions: { targetPage: 42 // Extract fields from specific page only (default: all pages) } // structure, // Options for PDF field discovery\n imageOptions: { format: \"png\" // options: \"png\", \"jpeg\" // Output image format, quality: 0.8 // default // JPEG quality (0.1-1.0, only for JPEG format), dpi: 150 // default // Output DPI (dots per inch), pages: [42] // Specific page numbers to convert (1-indexed). If not provided, converts all pages } // structure, // Options for PDF to images conversion\n aiOptions: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use for field identification, temperature: 0.3 // default // Temperature for AI responses (lower = more consistent), maxTokens: 50000 // default // Maximum tokens for AI response, jsonMode: true // default // Enable JSON mode to ensure clean JSON output } // structure, // AI agent configuration options\n});\n\nconst result = await pdfOcrWorkflow_identify.action();\n// outputSchema for result.data when operation === 'identify':\n// {\n// mode: \"identify\" // Result from identify mode,\n// extractedFields: { id: number, fieldName: string, confidence: number }[] // Array of identified fields with descriptive names,\n// discoveryData: { totalFields: number, fieldsWithCoordinates: number, pages: number[] } // Summary of field discovery results,\n// imageData: { totalPages: number, convertedPages: number, format: string, dpi: number } // Summary of image conversion results,\n// aiAnalysis: { model: string, iterations: number, processingTime: number | undefined } // AI analysis metadata,\n// success: boolean // Whether the workflow completed successfully,\n// error: string // Error message if workflow failed\n// }\n\n\n// Autofill example\nconst pdfOcrWorkflow_autofill = new PdfOcrWorkflowBubble({\n mode: \"autofill\", // Identify form fields and autofill with client information\n pdfData: \"example string\", // Base64 encoded PDF data\n clientInformation: \"example string\", // Free text containing client information to use for autofilling form fields\n discoveryOptions: { targetPage: 42 // Extract fields from specific page only (default: all pages) } // structure, // Options for PDF field discovery\n imageOptions: { format: \"png\" // options: \"png\", \"jpeg\" // Output image format, quality: 0.8 // default // JPEG quality (0.1-1.0, only for JPEG format), dpi: 150 // default // Output DPI (dots per inch), pages: [42] // Specific page numbers to convert (1-indexed). If not provided, converts all pages } // structure, // Options for PDF to images conversion\n aiOptions: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use for field identification and autofill, temperature: 0.3 // default // Temperature for AI responses (lower = more consistent), maxTokens: 50000 // default // Maximum tokens for AI response, jsonMode: true // default // Enable JSON mode to ensure clean JSON output } // structure, // AI agent configuration options\n});\n\nconst result = await pdfOcrWorkflow_autofill.action();\n// outputSchema for result.data when operation === 'autofill':\n// {\n// mode: \"autofill\" // Result from autofill mode,\n// extractedFields: { id: number, originalFieldName: string | undefined, fieldName: string, value: string, confidence: number }[] // Array of identified fields with values for autofill,\n// filledPdfData: string // Base64 encoded filled PDF data,\n// discoveryData: { totalFields: number, fieldsWithCoordinates: number, pages: number[] } // Summary of field discovery results,\n// imageData: { totalPages: number, convertedPages: number, format: string, dpi: number } // Summary of image conversion results,\n// aiAnalysis: { model: string, iterations: number, processingTime: number | undefined } // AI analysis metadata,\n// fillResults: { filledFields: number, successfullyFilled: number } // Summary of PDF filling results,\n// success: boolean // Whether the workflow completed successfully,\n// error: string // Error message if workflow failed\n// }\n\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`pdf-ocr-workflow failed: ${result.error}`);\n}\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
259
|
+
"requiredCredentials": [
|
|
260
|
+
"GOOGLE_GEMINI_CRED",
|
|
261
|
+
"OPENAI_CRED",
|
|
262
|
+
"ANTHROPIC_CRED",
|
|
263
|
+
"OPENROUTER_CRED"
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "generate-document-workflow",
|
|
268
|
+
"alias": "generate-doc",
|
|
269
|
+
"type": "workflow",
|
|
270
|
+
"shortDescription": "Generate Document workflow: convert markdown to structured formats using AI",
|
|
271
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
272
|
+
"inputSchema": "{\n documents: { content: string, index: number, metadata: { originalFilename: string | undefined, pageCount: number | undefined, uploadedImages: { pageNumber: number, fileName: string, fileUrl: string | undefined }[] | undefined } | undefined }[] // Array of document objects with content, index, and metadata,\n outputDescription: string // Description of what the user wants to extract (e.g., \"expense tracking with vendor, amount, date, category\"),\n outputFormat: \"html\" | \"csv\" | \"json\" // Output format for the structured data,\n aiOptions: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\", temperature: number, maxTokens: number, jsonMode: boolean } // AI agent configuration options,\n credentials: Record<string, string> | undefined // Credentials for AI model access (GOOGLE_GEMINI_CRED, OPENAI_CRED, etc.)\n}",
|
|
273
|
+
"outputSchema": "{\n columns: { name: string, type: \"string\" | \"number\" | \"integer\" | \"float\" | \"date\" | \"boolean\", description: string }[] // Column definitions for the structured data,\n rows: Record<string, unknown>[] // Array of data rows extracted from documents,\n metadata: { totalDocuments: number, totalRows: number, totalColumns: number, processingTime: number, extractedFrom: string[] } // Metadata about the extraction process,\n generatedFiles: { html: string | undefined, csv: string | undefined, json: string | undefined } // Generated files in requested formats,\n aiAnalysis: { model: string, iterations: number, processingTime: number | undefined } // AI analysis metadata,\n success: boolean // Whether the workflow completed successfully,\n error: string // Error message if workflow failed\n}",
|
|
274
|
+
"usageExample": "// Example usage of generate-document-workflow bubble\nconst generateDocumentWorkflow = new GenerateDocumentWorkflowBubble({\n documents: [{ content: \"example string\", index: 42, metadata: { originalFilename: \"example string\", pageCount: 42, uploadedImages: [{ pageNumber: 42, fileName: \"example string\", fileUrl: \"example string\" }] } }], // Array of document objects with content, index, and metadata,\n outputDescription: \"example string\", // Description of what the user wants to extract (e.g., \"expense tracking with vendor, amount, date, category\"),\n outputFormat: \"html\" // options: \"html\", \"csv\", \"json\", // Output format for the structured data,\n aiOptions: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use for document analysis, temperature: 0.1 // default // Temperature for AI responses (lower = more consistent), maxTokens: 50000 // default // Maximum tokens for AI response, jsonMode: true // default // Enable JSON mode to ensure clean JSON output } // structure, // AI agent configuration options,\n});\n\nconst result = await generateDocumentWorkflow.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// columns: { name: string, type: \"string\" | \"number\" | \"integer\" | \"float\" | \"date\" | \"boolean\", description: string }[] // Column definitions for the structured data,\n// rows: Record<string, unknown>[] // Array of data rows extracted from documents,\n// metadata: { totalDocuments: number, totalRows: number, totalColumns: number, processingTime: number, extractedFrom: string[] } // Metadata about the extraction process,\n// generatedFiles: { html: string | undefined, csv: string | undefined, json: string | undefined } // Generated files in requested formats,\n// aiAnalysis: { model: string, iterations: number, processingTime: number | undefined } // AI analysis metadata,\n// success: boolean // Whether the workflow completed successfully,\n// error: string // Error message if workflow failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
275
|
+
"requiredCredentials": [
|
|
276
|
+
"GOOGLE_GEMINI_CRED",
|
|
277
|
+
"OPENAI_CRED",
|
|
278
|
+
"ANTHROPIC_CRED",
|
|
279
|
+
"OPENROUTER_CRED"
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"name": "parse-document-workflow",
|
|
284
|
+
"alias": "parse-doc",
|
|
285
|
+
"type": "workflow",
|
|
286
|
+
"shortDescription": "Parse Document workflow: convert PDFs/images to markdown using AI vision",
|
|
287
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
288
|
+
"inputSchema": "{\n documentData: string // Base64 encoded document data (PDF or image) OR R2 file URL starting with https://,\n documentType: \"pdf\" | \"image\" // Type of document being processed,\n isFileUrl: boolean | undefined // Set to true if documentData is an R2 file URL instead of base64,\n conversionOptions: { preserveStructure: boolean, includeVisualDescriptions: boolean, extractNumericalData: boolean, combinePages: boolean } // Options for document conversion and parsing,\n imageOptions: { format: \"png\" | \"jpeg\", quality: number, dpi: number, pages: number[] | undefined } // Options for PDF to images conversion,\n aiOptions: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\", temperature: number, maxTokens: number, jsonMode: boolean } // AI agent configuration options,\n storageOptions: { uploadImages: boolean, bucketName: string | undefined, pageImageUrls: { pageNumber: number, uploadUrl: string, fileName: string }[] | undefined, userId: string | undefined } | undefined // Storage options for uploading page images,\n credentials: Record<string, string> | undefined // Credentials for AI model access (GOOGLE_GEMINI_CRED, OPENAI_CRED, etc.)\n}",
|
|
289
|
+
"outputSchema": "{\n markdown: string // Generated markdown content from the document,\n pages: { pageNumber: number, markdown: string, hasCharts: boolean, hasTables: boolean, hasImages: boolean }[] // Per-page analysis results,\n metadata: { totalPages: number, processedPages: number, hasVisualElements: boolean, processingTime: number, imageFormat: string, imageDpi: number } // Metadata about the parsing process,\n conversionSummary: { totalCharacters: number, tablesExtracted: number, chartsDescribed: number, imagesDescribed: number } // Summary of conversion results,\n aiAnalysis: { model: string, iterations: number, processingTime: number } // AI analysis metadata,\n uploadedImages: { pageNumber: number, fileName: string, fileUrl: string | undefined, uploaded: boolean }[] | undefined // Information about uploaded page images,\n success: boolean // Whether the workflow completed successfully,\n error: string // Error message if workflow failed\n}",
|
|
290
|
+
"usageExample": "// Example usage of parse-document-workflow bubble\nconst parseDocumentWorkflow = new ParseDocumentWorkflowBubble({\n documentData: \"example string\", // Base64 encoded document data (PDF or image) OR R2 file URL starting with https://,\n documentType: \"pdf\" // options: \"pdf\", \"image\", // Type of document being processed,\n isFileUrl: false // default, // Set to true if documentData is an R2 file URL instead of base64,\n conversionOptions: { preserveStructure: true // default // Maintain original document structure and hierarchy, includeVisualDescriptions: true // default // Include detailed descriptions of charts, images, and diagrams, extractNumericalData: true // default // Extract specific numerical values from charts and tables, combinePages: false // default // Deprecated: Pages are always kept separate with clear headers } // structure, // Options for document conversion and parsing,\n imageOptions: { format: \"png\" // options: \"png\", \"jpeg\" // Output image format for PDF conversion, quality: 0.9 // default // Image quality (0.1-1.0, higher = better quality), dpi: 200 // default // Output DPI for PDF conversion (higher = better quality), pages: [42] // Specific page numbers to process (1-indexed) } // structure, // Options for PDF to images conversion,\n aiOptions: { model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\" // AI model to use for document analysis and conversion, temperature: 0.4 // default // Temperature for AI responses (balanced for accuracy vs recitation), maxTokens: 2000 // default // Maximum tokens for AI response, jsonMode: false // default // Use JSON mode for structured output } // structure, // AI agent configuration options,\n storageOptions: { uploadImages: false // default // Whether to upload converted page images to S3, bucketName: \"example string\" // S3 bucket name for image uploads, pageImageUrls: [{ pageNumber: 42, uploadUrl: \"example string\", fileName: \"example string\" }] // Pre-generated upload URLs for page images, userId: \"example string\" // User ID for secure file isolation }, // Storage options for uploading page images,\n});\n\nconst result = await parseDocumentWorkflow.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// markdown: string // Generated markdown content from the document,\n// pages: { pageNumber: number, markdown: string, hasCharts: boolean, hasTables: boolean, hasImages: boolean }[] // Per-page analysis results,\n// metadata: { totalPages: number, processedPages: number, hasVisualElements: boolean, processingTime: number, imageFormat: string, imageDpi: number } // Metadata about the parsing process,\n// conversionSummary: { totalCharacters: number, tablesExtracted: number, chartsDescribed: number, imagesDescribed: number } // Summary of conversion results,\n// aiAnalysis: { model: string, iterations: number, processingTime: number } // AI analysis metadata,\n// uploadedImages: { pageNumber: number, fileName: string, fileUrl: string | undefined, uploaded: boolean }[] | undefined // Information about uploaded page images,\n// success: boolean // Whether the workflow completed successfully,\n// error: string // Error message if workflow failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
291
|
+
"requiredCredentials": [
|
|
292
|
+
"GOOGLE_GEMINI_CRED",
|
|
293
|
+
"OPENAI_CRED",
|
|
294
|
+
"ANTHROPIC_CRED",
|
|
295
|
+
"OPENROUTER_CRED",
|
|
296
|
+
"CLOUDFLARE_R2_ACCESS_KEY",
|
|
297
|
+
"CLOUDFLARE_R2_SECRET_KEY",
|
|
298
|
+
"CLOUDFLARE_R2_ACCOUNT_ID"
|
|
299
|
+
]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"name": "get-bubble-details-tool",
|
|
303
|
+
"alias": "details",
|
|
304
|
+
"type": "tool",
|
|
305
|
+
"shortDescription": "Provides detailed information about a specific bubble, including schema, parameters, and documentation",
|
|
306
|
+
"useCase": "- AI agent understanding of specific bubble capabilities",
|
|
307
|
+
"inputSchema": "{\n bubbleName: string // The name of the bubble to get details about,\n includeInputSchema: boolean | undefined // Include input parameter schema in the response,\n credentials: Record<string, string> | undefined // Object mapping credential types to values (injected at runtime)\n}",
|
|
308
|
+
"outputSchema": "{\n name: string // Name of the bubble,\n alias: string | undefined // Short alias for the bubble,\n inputSchema: string | undefined // String representation of the input parameter schema types,\n outputSchema: string // String representation of the output schema types,\n usageExample: string // Code example showing how to use the bubble,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
309
|
+
"usageExample": "// Example usage of get-bubble-details-tool bubble\nconst getBubbleDetailsTool = new GetBubbleDetailsToolBubble({\n bubbleName: \"example string\", // The name of the bubble to get details about,\n includeInputSchema: false // default, // Include input parameter schema in the response,\n});\n\nconst result = await getBubbleDetailsTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// name: string // Name of the bubble,\n// alias: string | undefined // Short alias for the bubble,\n// inputSchema: string | undefined // String representation of the input parameter schema types,\n// outputSchema: string // String representation of the output schema types,\n// usageExample: string // Code example showing how to use the bubble,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
310
|
+
"requiredCredentials": []
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"name": "list-bubbles-tool",
|
|
314
|
+
"alias": "list",
|
|
315
|
+
"type": "tool",
|
|
316
|
+
"shortDescription": "Lists all available bubbles in the registry",
|
|
317
|
+
"useCase": "- AI agent discovery of available capabilities",
|
|
318
|
+
"inputSchema": "Complex schema - see usage example for structure",
|
|
319
|
+
"outputSchema": "{\n bubbles: { name: string, alias: string | undefined, shortDescription: string, useCase: string, type: string }[] // Array of bubble information objects,\n totalCount: number // Total number of bubbles in the registry,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
320
|
+
"usageExample": "// Example usage of list-bubbles-tool bubble\nconst listBubblesTool = new ListBubblesToolBubble({\n // Add required parameters here\n});\n\nconst result = await listBubblesTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// bubbles: { name: string, alias: string | undefined, shortDescription: string, useCase: string, type: string }[] // Array of bubble information objects,\n// totalCount: number // Total number of bubbles in the registry,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
321
|
+
"requiredCredentials": []
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"name": "sql-query-tool",
|
|
325
|
+
"alias": "sql",
|
|
326
|
+
"type": "tool",
|
|
327
|
+
"shortDescription": "Execute read-only SQL queries against PostgreSQL databases for data analysis",
|
|
328
|
+
"useCase": "- AI agents performing iterative database exploration",
|
|
329
|
+
"inputSchema": "{\n query: string // SQL query to execute (SELECT, WITH, EXPLAIN, ANALYZE, SHOW, DESCRIBE only),\n reasoning: string // Explain why you're running this specific query and what you hope to learn from it,\n credentials: Record<string, string> | undefined // Database credentials (injected at runtime),\n config: Record<string, unknown> | undefined // Configuration for the tool bubble\n}",
|
|
330
|
+
"outputSchema": "{\n rows: Record<string, unknown>[] | undefined // Array of query result rows as objects,\n rowCount: number // Number of rows returned by the query,\n executionTime: number // Query execution time in milliseconds,\n fields: { name: string, dataTypeID: number | undefined }[] | undefined // Array of column metadata from the query result,\n success: boolean // Whether the query execution was successful,\n error: string // Error message if query execution failed\n}",
|
|
331
|
+
"usageExample": "// Example usage of sql-query-tool bubble\nconst sqlQueryTool = new SqlQueryToolBubble({\n query: \"example string\", // SQL query to execute (SELECT, WITH, EXPLAIN, ANALYZE, SHOW, DESCRIBE only),\n reasoning: \"example string\", // Explain why you're running this specific query and what you hope to learn from it,\n config: {} // record/object with string keys, // Configuration for the tool bubble,\n});\n\nconst result = await sqlQueryTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// rows: Record<string, unknown>[] | undefined // Array of query result rows as objects,\n// rowCount: number // Number of rows returned by the query,\n// executionTime: number // Query execution time in milliseconds,\n// fields: { name: string, dataTypeID: number | undefined }[] | undefined // Array of column metadata from the query result,\n// success: boolean // Whether the query execution was successful,\n// error: string // Error message if query execution failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
332
|
+
"requiredCredentials": []
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"name": "chart-js-tool",
|
|
336
|
+
"alias": "chart",
|
|
337
|
+
"type": "tool",
|
|
338
|
+
"shortDescription": "Generate Chart.js configurations from data for interactive visualizations",
|
|
339
|
+
"useCase": "- Converting SQL query results into visual charts",
|
|
340
|
+
"inputSchema": "{\n data: Record<string, unknown>[] // Array of data objects (typically from SQL query results),\n chartType: \"line\" | \"bar\" | \"pie\" | \"doughnut\" | \"radar\" | \"scatter\" | \"bubble\" | \"polarArea\" // Type of chart to generate,\n xColumn: string | undefined // Column name to use for X-axis (auto-detected if not provided),\n yColumn: string | undefined // Column name to use for Y-axis (auto-detected if not provided),\n groupByColumn: string | undefined // Column to group data by for multiple series,\n options: { title: string | undefined, xAxisLabel: string | undefined, yAxisLabel: string | undefined, colorScheme: \"default\" | \"viridis\" | \"plasma\" | \"inferno\" | \"magma\" | \"blues\" | \"greens\" | \"reds\" | \"oranges\" | \"categorical\", responsive: boolean, maintainAspectRatio: boolean, showLegend: boolean, showTooltips: boolean } | undefined // Chart customization options,\n advancedConfig: Record<string, unknown> | undefined // Advanced Chart.js configuration object (overrides simple options),\n reasoning: string // Explain why this chart type and configuration was chosen,\n generateFile: boolean // Generate an actual chart image file (PNG format),\n filePath: string | undefined // Custom file path for generated chart (defaults to temp directory),\n fileName: string | undefined // Custom file name for generated chart (defaults to auto-generated name),\n width: number | undefined // Chart width in pixels (default: 800),\n height: number | undefined // Chart height in pixels (default: 600),\n credentials: Record<string, string> | undefined // Credentials (HIDDEN from AI - injected at runtime),\n config: Record<string, unknown> | undefined // Configuration for the tool bubble (HIDDEN from AI - injected at runtime)\n}",
|
|
341
|
+
"outputSchema": "{\n chartConfig: Record<string, unknown> // Complete Chart.js configuration object,\n chartType: string // Chart type that was generated,\n datasetCount: number // Number of datasets in the chart,\n dataPointCount: number // Total number of data points,\n suggestedSize: { width: number, height: number } // Suggested canvas size for the chart,\n metadata: { xColumn: string | undefined, yColumn: string | undefined, groupByColumn: string | undefined, colorScheme: string, generatedAt: string } // Metadata about chart generation,\n filePath: string | undefined // Path to generated chart file (if generateFile was true),\n fileExists: boolean | undefined // Whether the generated file exists on disk,\n fileSize: number | undefined // Size of generated file in bytes,\n success: boolean,\n error: string\n}",
|
|
342
|
+
"usageExample": "// Example usage of chart-js-tool bubble\nconst chartJsTool = new ChartJsToolBubble({\n data: [{} // record/object with string keys], // Array of data objects (typically from SQL query results),\n chartType: \"line\" // options: \"line\", \"bar\", \"pie\", \"doughnut\", \"radar\", \"scatter\", \"bubble\", \"polarArea\", // Type of chart to generate,\n xColumn: \"example string\", // Column name to use for X-axis (auto-detected if not provided),\n yColumn: \"example string\", // Column name to use for Y-axis (auto-detected if not provided),\n groupByColumn: \"example string\", // Column to group data by for multiple series,\n options: { title: \"example string\" // Chart title, xAxisLabel: \"example string\" // X-axis label, yAxisLabel: \"example string\" // Y-axis label, colorScheme: \"default\" // options: \"default\", \"viridis\", \"plasma\", \"inferno\", \"magma\", \"blues\", \"greens\", \"reds\", \"oranges\", \"categorical\" // Color scheme for the chart, responsive: true // default // Make chart responsive, maintainAspectRatio: true // default // Maintain aspect ratio, showLegend: true // default // Show chart legend, showTooltips: true // default // Show tooltips on hover }, // Chart customization options,\n advancedConfig: {} // record/object with string keys, // Advanced Chart.js configuration object (overrides simple options),\n reasoning: \"example string\", // Explain why this chart type and configuration was chosen,\n generateFile: false // default, // Generate an actual chart image file (PNG format),\n filePath: \"example string\", // Custom file path for generated chart (defaults to temp directory),\n fileName: \"example string\", // Custom file name for generated chart (defaults to auto-generated name),\n width: 800 // default, // Chart width in pixels (default: 800),\n height: 600 // default, // Chart height in pixels (default: 600),\n config: {} // record/object with string keys, // Configuration for the tool bubble (HIDDEN from AI - injected at runtime),\n});\n\nconst result = await chartJsTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// chartConfig: Record<string, unknown> // Complete Chart.js configuration object,\n// chartType: string // Chart type that was generated,\n// datasetCount: number // Number of datasets in the chart,\n// dataPointCount: number // Total number of data points,\n// suggestedSize: { width: number, height: number } // Suggested canvas size for the chart,\n// metadata: { xColumn: string | undefined, yColumn: string | undefined, groupByColumn: string | undefined, colorScheme: string, generatedAt: string } // Metadata about chart generation,\n// filePath: string | undefined // Path to generated chart file (if generateFile was true),\n// fileExists: boolean | undefined // Whether the generated file exists on disk,\n// fileSize: number | undefined // Size of generated file in bytes,\n// success: boolean,\n// error: string\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
343
|
+
"requiredCredentials": []
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"name": "bubbleflow-validation-tool",
|
|
347
|
+
"alias": "validate-bubbleflow",
|
|
348
|
+
"type": "tool",
|
|
349
|
+
"shortDescription": "Validates BubbleFlow TypeScript code for syntax and structure",
|
|
350
|
+
"useCase": "- When an AI agent needs to validate user-provided BubbleFlow code",
|
|
351
|
+
"inputSchema": "{\n code: string // TypeScript code to validate,\n options: { includeDetails: boolean, strictMode: boolean } | undefined // Validation configuration options,\n credentials: Record<string, string> | undefined // Credentials (HIDDEN from AI - injected at runtime),\n config: Record<string, unknown> | undefined // Configuration for the validation tool (HIDDEN from AI - injected at runtime)\n}",
|
|
352
|
+
"outputSchema": "{\n valid: boolean // Whether the code is valid,\n errors: string[] | undefined // List of validation errors if any,\n bubbleCount: number | undefined // Number of bubbles found in the code,\n bubbles: { variableName: string, bubbleName: string, className: string, hasAwait: boolean, hasActionCall: boolean, parameterCount: number }[] | undefined // Details about each bubble found,\n metadata: { validatedAt: string, codeLength: number, strictMode: boolean },\n success: boolean // Whether the validation operation was successful,\n error: string // Error message if validation failed\n}",
|
|
353
|
+
"usageExample": "// Example usage of bubbleflow-validation-tool bubble\nconst bubbleflowValidationTool = new BubbleflowValidationToolBubble({\n code: \"example string\", // TypeScript code to validate,\n options: { includeDetails: true // default // Include detailed bubble analysis, strictMode: true // default // Enable strict TypeScript validation }, // Validation configuration options,\n config: {} // record/object with string keys, // Configuration for the validation tool (HIDDEN from AI - injected at runtime),\n});\n\nconst result = await bubbleflowValidationTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// valid: boolean // Whether the code is valid,\n// errors: string[] | undefined // List of validation errors if any,\n// bubbleCount: number | undefined // Number of bubbles found in the code,\n// bubbles: { variableName: string, bubbleName: string, className: string, hasAwait: boolean, hasActionCall: boolean, parameterCount: number }[] | undefined // Details about each bubble found,\n// metadata: { validatedAt: string, codeLength: number, strictMode: boolean },\n// success: boolean // Whether the validation operation was successful,\n// error: string // Error message if validation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
354
|
+
"requiredCredentials": []
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"name": "web-search-tool",
|
|
358
|
+
"alias": "websearch",
|
|
359
|
+
"type": "tool",
|
|
360
|
+
"shortDescription": "Performs web searches using Firecrawl to find current information from the web",
|
|
361
|
+
"useCase": "- Finding current events and news",
|
|
362
|
+
"inputSchema": "{\n query: string // The search query to execute,\n limit: number // Maximum number of search results to return,\n location: string | undefined // Location parameter for search results (e.g., \"us\", \"uk\"),\n credentials: Record<string, string> | undefined // Required credentials including FIRECRAWL_API_KEY\n}",
|
|
363
|
+
"outputSchema": "{\n results: { title: string, url: string, content: string }[] // Array of search results with title, URL, and content,\n query: string // The original search query,\n totalResults: number // Number of results returned,\n searchEngine: string // Search engine used (Firecrawl),\n success: boolean // Whether the search was successful,\n error: string // Error message if search failed\n}",
|
|
364
|
+
"usageExample": "// Example usage of web-search-tool bubble\nconst webSearchTool = new WebSearchToolBubble({\n query: \"example string\", // The search query to execute,\n limit: 3 // default, // Maximum number of search results to return,\n location: \"example string\", // Location parameter for search results (e.g., \"us\", \"uk\"),\n});\n\nconst result = await webSearchTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// results: { title: string, url: string, content: string }[] // Array of search results with title, URL, and content,\n// query: string // The original search query,\n// totalResults: number // Number of results returned,\n// searchEngine: string // Search engine used (Firecrawl),\n// success: boolean // Whether the search was successful,\n// error: string // Error message if search failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
365
|
+
"requiredCredentials": [
|
|
366
|
+
"FIRECRAWL_API_KEY"
|
|
367
|
+
]
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"name": "web-scrape-tool",
|
|
371
|
+
"alias": "scrape",
|
|
372
|
+
"type": "tool",
|
|
373
|
+
"shortDescription": "Scrapes content from a single web page using Firecrawl, good to use after web-search-tool to get the full content of a page",
|
|
374
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
375
|
+
"inputSchema": "{\n url: string // The URL to scrape content from,\n format: \"markdown\" // Content format to extract (default: markdown),\n onlyMainContent: boolean // Extract only main content, filtering out navigation/footers,\n actions: { type: \"wait\" | \"click\" | \"write\" | \"press\" | \"scroll\" | \"executeJavascript\", milliseconds: number | undefined, selector: string | undefined, text: string | undefined, key: string | undefined, direction: \"up\" | \"down\" | undefined, script: string | undefined }[] | undefined // Optional browser actions for authentication/navigation (e.g., login flows),\n headers: Record<string, string> | undefined // Optional HTTP headers (e.g., for session cookies),\n waitFor: number // Time to wait for dynamic content in milliseconds (default: 3000),\n credentials: Record<string, string> | undefined // Required credentials including FIRECRAWL_API_KEY\n}",
|
|
376
|
+
"outputSchema": "{\n content: string // Scraped content in requested format,\n title: string // Page title if available,\n url: string // The original URL that was scraped,\n format: string // Format of the returned content,\n success: boolean // Whether the scraping was successful,\n error: string // Error message if scraping failed,\n metadata: { statusCode: number | undefined, loadTime: number | undefined } | undefined // Additional metadata about the scrape\n}",
|
|
377
|
+
"usageExample": "// Example usage of web-scrape-tool bubble\nconst webScrapeTool = new WebScrapeToolBubble({\n url: \"example string\", // The URL to scrape content from,\n format: \"markdown\", // Content format to extract (default: markdown),\n onlyMainContent: true // default, // Extract only main content, filtering out navigation/footers,\n actions: [{ type: \"wait\" // options: \"wait\", \"click\", \"write\", \"press\", \"scroll\", \"executeJavascript\" // Action type to perform, milliseconds: 42 // Time to wait in milliseconds (for wait), selector: \"example string\" // CSS selector to interact with (wait/click/write/scroll), text: \"example string\" // Text to write (for write), key: \"example string\" // Key to press (e.g., \"Enter\") (for press), direction: \"up\" // options: \"up\", \"down\" // Scroll direction (for scroll), script: \"example string\" // JavaScript code (for executeJavascript) }], // Optional browser actions for authentication/navigation (e.g., login flows),\n headers: { \"example_key\": \"example string\" } // record/object with string keys, // Optional HTTP headers (e.g., for session cookies),\n waitFor: 3000 // default, // Time to wait for dynamic content in milliseconds (default: 3000),\n});\n\nconst result = await webScrapeTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// content: string // Scraped content in requested format,\n// title: string // Page title if available,\n// url: string // The original URL that was scraped,\n// format: string // Format of the returned content,\n// success: boolean // Whether the scraping was successful,\n// error: string // Error message if scraping failed,\n// metadata: { statusCode: number | undefined, loadTime: number | undefined } | undefined // Additional metadata about the scrape\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
378
|
+
"requiredCredentials": [
|
|
379
|
+
"FIRECRAWL_API_KEY"
|
|
380
|
+
]
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"name": "web-extract-tool",
|
|
384
|
+
"alias": "extract",
|
|
385
|
+
"type": "tool",
|
|
386
|
+
"shortDescription": "Extracts structured data from web pages using Firecrawl AI-powered extraction with custom prompts and schemas",
|
|
387
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
388
|
+
"inputSchema": "{\n url: string // The URL to extract structured data from,\n prompt: string // Detailed prompt describing what data to extract from the web page,\n schema: string // JSON schema string defining the structure of the data to extract,\n timeout: number | undefined // Timeout in milliseconds for the extraction (default: 30000),\n credentials: Record<string, string> | undefined // Required credentials including FIRECRAWL_API_KEY\n}",
|
|
389
|
+
"outputSchema": "{\n url: string // The original URL that was processed,\n success: boolean // Whether the extraction was successful,\n error: string // Error message if extraction failed,\n extractedData: unknown // The extracted structured data matching the provided schema,\n metadata: { extractionTime: number | undefined, pageTitle: string | undefined, statusCode: number | undefined } | undefined // Additional metadata about the extraction\n}",
|
|
390
|
+
"usageExample": "// Example usage of web-extract-tool bubble\nconst webExtractTool = new WebExtractToolBubble({\n url: \"example string\", // The URL to extract structured data from,\n prompt: \"example string\", // Detailed prompt describing what data to extract from the web page,\n schema: \"example string\", // JSON schema string defining the structure of the data to extract,\n timeout: 30000 // default, // Timeout in milliseconds for the extraction (default: 30000),\n});\n\nconst result = await webExtractTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// url: string // The original URL that was processed,\n// success: boolean // Whether the extraction was successful,\n// error: string // Error message if extraction failed,\n// extractedData: unknown // The extracted structured data matching the provided schema,\n// metadata: { extractionTime: number | undefined, pageTitle: string | undefined, statusCode: number | undefined } | undefined // Additional metadata about the extraction\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
391
|
+
"requiredCredentials": [
|
|
392
|
+
"FIRECRAWL_API_KEY"
|
|
393
|
+
]
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"name": "research-agent-tool",
|
|
397
|
+
"alias": "research",
|
|
398
|
+
"type": "tool",
|
|
399
|
+
"shortDescription": "AI-powered research agent that searches and scrapes the internet to gather structured information",
|
|
400
|
+
"useCase": "- Market research with structured competitor analysis",
|
|
401
|
+
"inputSchema": "{\n task: string // The research task that requires searching the internet and gathering information,\n expectedResultSchema: string // JSON schema string that defines the expected structure of the research result. Out,\n model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"openai/gpt-o4-mini\" | \"openai/gpt-4o\" | \"google/gemini-2.5-pro\" | \"google/gemini-2.5-flash\" | \"google/gemini-2.5-flash-lite\" | \"google/gemini-2.5-flash-image-preview\" | \"anthropic/claude-sonnet-4-5-20250929\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" | undefined // Model to use for the research agent (default: google/gemini-2.5-flash),\n maxTokens: number | undefined // Maximum number of tokens for the research agent (default: 40000),\n maxIterations: number // Maximum number of iterations for the research agent (default: 100),\n credentials: Record<string, string> | undefined // Required credentials\n}",
|
|
402
|
+
"outputSchema": "{\n result: unknown // The research result matching the expected JSON schema structure, parsed to object,\n summary: string // 1-2 sentence summary of what research was conducted and completed,\n sourcesUsed: string[] // Array of URLs and sources that were searched and scraped during research,\n iterationsUsed: number // Number of AI agent iterations used to complete the research,\n success: boolean // Whether the research task was completed successfully,\n error: string // Error message if research failed\n}",
|
|
403
|
+
"usageExample": "// Example usage of research-agent-tool bubble\nconst researchAgentTool = new ResearchAgentToolBubble({\n task: \"example string\", // The research task that requires searching the internet and gathering information,\n expectedResultSchema: \"example string\", // JSON schema string that defines the expected structure of the research result. Out,\n model: \"openai/gpt-5\" // options: \"openai/gpt-5\", \"openai/gpt-5-mini\", \"openai/gpt-o4-mini\", \"openai/gpt-4o\", \"google/gemini-2.5-pro\", \"google/gemini-2.5-flash\", \"google/gemini-2.5-flash-lite\", \"google/gemini-2.5-flash-image-preview\", \"anthropic/claude-sonnet-4-5-20250929\", \"openrouter/x-ai/grok-code-fast-1\", \"openrouter/z-ai/glm-4.6\", // Model to use for the research agent (default: google/gemini-2.5-flash),\n maxTokens: 40000 // default, // Maximum number of tokens for the research agent (default: 40000),\n maxIterations: 100 // default, // Maximum number of iterations for the research agent (default: 100),\n});\n\nconst result = await researchAgentTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// result: unknown // The research result matching the expected JSON schema structure, parsed to object,\n// summary: string // 1-2 sentence summary of what research was conducted and completed,\n// sourcesUsed: string[] // Array of URLs and sources that were searched and scraped during research,\n// iterationsUsed: number // Number of AI agent iterations used to complete the research,\n// success: boolean // Whether the research task was completed successfully,\n// error: string // Error message if research failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
404
|
+
"requiredCredentials": [
|
|
405
|
+
"FIRECRAWL_API_KEY",
|
|
406
|
+
"GOOGLE_GEMINI_CRED"
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"name": "reddit-scrape-tool",
|
|
411
|
+
"alias": "reddit",
|
|
412
|
+
"type": "tool",
|
|
413
|
+
"shortDescription": "Scrapes posts from any Reddit subreddit with flexible filtering and sorting options",
|
|
414
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
415
|
+
"inputSchema": "{\n subreddit: string // Name of the subreddit to scrape (without r/ prefix),\n limit: number // Maximum number of posts to fetch (1-500, default: 25),\n sort: \"hot\" | \"new\" | \"top\" | \"rising\" // Sorting method for posts (default: hot),\n timeFilter: \"hour\" | \"day\" | \"week\" | \"month\" | \"year\" | \"all\" | undefined // Time filter for \"top\" sort (only applies when sort=top),\n filterToday: boolean // Filter results to only include posts from today,\n includeStickied: boolean // Include stickied/pinned posts in results,\n minScore: number | undefined // Minimum upvote score required for posts,\n credentials: Record<string, string> | undefined // Optional credentials for enhanced features\n}",
|
|
416
|
+
"outputSchema": "{\n posts: { title: string, url: string, author: string, score: number, numComments: number, createdUtc: number, postUrl: string, selftext: string, subreddit: string, postHint: string | null | undefined, isSelf: boolean, thumbnail: string | undefined, domain: string | undefined, flair: string | undefined }[] // Array of scraped Reddit posts,\n metadata: { subreddit: string, requestedLimit: number, actualCount: number, filteredCount: number, sort: string, timeFilter: string | undefined, scrapedAt: string, apiEndpoint: string } // Metadata about the scraping operation,\n success: boolean // Whether the scraping was successful,\n error: string // Error message if scraping failed\n}",
|
|
417
|
+
"usageExample": "// Example usage of reddit-scrape-tool bubble\nconst redditScrapeTool = new RedditScrapeToolBubble({\n subreddit: \"example string\", // Name of the subreddit to scrape (without r/ prefix),\n limit: 25 // default, // Maximum number of posts to fetch (1-500, default: 25),\n sort: \"hot\" // options: \"hot\", \"new\", \"top\", \"rising\", // Sorting method for posts (default: hot),\n timeFilter: \"hour\" // options: \"hour\", \"day\", \"week\", \"month\", \"year\", \"all\", // Time filter for \"top\" sort (only applies when sort=top),\n filterToday: false // default, // Filter results to only include posts from today,\n includeStickied: false // default, // Include stickied/pinned posts in results,\n minScore: 42, // Minimum upvote score required for posts,\n});\n\nconst result = await redditScrapeTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// posts: { title: string, url: string, author: string, score: number, numComments: number, createdUtc: number, postUrl: string, selftext: string, subreddit: string, postHint: string | null | undefined, isSelf: boolean, thumbnail: string | undefined, domain: string | undefined, flair: string | undefined }[] // Array of scraped Reddit posts,\n// metadata: { subreddit: string, requestedLimit: number, actualCount: number, filteredCount: number, sort: string, timeFilter: string | undefined, scrapedAt: string, apiEndpoint: string } // Metadata about the scraping operation,\n// success: boolean // Whether the scraping was successful,\n// error: string // Error message if scraping failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
418
|
+
"requiredCredentials": []
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"name": "instagram-tool",
|
|
422
|
+
"alias": "ig",
|
|
423
|
+
"type": "tool",
|
|
424
|
+
"shortDescription": "Scrape Instagram profiles and posts with a simple, unified interface. Works with individual user profiles and hashtags.",
|
|
425
|
+
"useCase": "**",
|
|
426
|
+
"inputSchema": "{\n operation: \"scrapeProfile\" | \"scrapeHashtag\" // Operation to perform: scrapeProfile for user profiles, scrapeHashtag for hashtag posts,\n profiles: string[] | undefined // Instagram usernames or profile URLs to scrape (for scrapeProfile operation). Examples: [\"@username\", \"https://www.instagram.com/username/\"],\n hashtags: string[] | undefined // Hashtags to scrape (for scrapeHashtag operation). Examples: [\"ai\", \"tech\"] or [\"https://www.instagram.com/explore/tags/ai\"],\n limit: number | undefined // Maximum number of posts to fetch (default: 20 for profiles, 50 for hashtags),\n credentials: Record<string, string> | undefined // Required credentials (auto-injected)\n}",
|
|
427
|
+
"outputSchema": "{\n operation: \"scrapeProfile\" | \"scrapeHashtag\" // Operation that was performed,\n posts: { url: string | null, caption: string | null, likesCount: number | null, commentsCount: number | null, ownerUsername: string | null, timestamp: string | null, type: \"image\" | \"video\" | \"carousel\" | null, displayUrl: string | null, hashtags: string[] | null }[] // Array of Instagram posts scraped,\n profiles: { username: string, fullName: string | null, bio: string | null, followersCount: number | null, followingCount: number | null, postsCount: number | null, isVerified: boolean | null, profilePicUrl: string | null }[] | undefined // Profile information for each scraped profile (only for scrapeProfile operation),\n scrapedHashtags: string[] | undefined // List of hashtags that were scraped (only for scrapeHashtag operation),\n scrapedProfiles: string[] | undefined // List of profile usernames that were scraped (only for scrapeProfile operation),\n totalPosts: number // Total number of posts scraped,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
428
|
+
"usageExample": "// Example usage of instagram-tool bubble\nconst instagramTool = new InstagramToolBubble({\n operation: \"scrapeProfile\" // options: \"scrapeProfile\", \"scrapeHashtag\", // Operation to perform: scrapeProfile for user profiles, scrapeHashtag for hashtag posts,\n profiles: [\"example string\"], // Instagram usernames or profile URLs to scrape (for scrapeProfile operation). Examples: [\"@username\", \"https://www.instagram.com/username/\"],\n hashtags: [\"example string\"], // Hashtags to scrape (for scrapeHashtag operation). Examples: [\"ai\", \"tech\"] or [\"https://www.instagram.com/explore/tags/ai\"],\n limit: 20 // default, // Maximum number of posts to fetch (default: 20 for profiles, 50 for hashtags),\n});\n\nconst result = await instagramTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// operation: \"scrapeProfile\" | \"scrapeHashtag\" // Operation that was performed,\n// posts: { url: string | null, caption: string | null, likesCount: number | null, commentsCount: number | null, ownerUsername: string | null, timestamp: string | null, type: \"image\" | \"video\" | \"carousel\" | null, displayUrl: string | null, hashtags: string[] | null }[] // Array of Instagram posts scraped,\n// profiles: { username: string, fullName: string | null, bio: string | null, followersCount: number | null, followingCount: number | null, postsCount: number | null, isVerified: boolean | null, profilePicUrl: string | null }[] | undefined // Profile information for each scraped profile (only for scrapeProfile operation),\n// scrapedHashtags: string[] | undefined // List of hashtags that were scraped (only for scrapeHashtag operation),\n// scrapedProfiles: string[] | undefined // List of profile usernames that were scraped (only for scrapeProfile operation),\n// totalPosts: number // Total number of posts scraped,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
429
|
+
"requiredCredentials": [
|
|
430
|
+
"APIFY_CRED"
|
|
431
|
+
]
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"name": "linkedin-tool",
|
|
435
|
+
"alias": "li",
|
|
436
|
+
"type": "tool",
|
|
437
|
+
"shortDescription": "Scrape LinkedIn posts by profile or search by keyword. Get engagement metrics, media, and complete metadata.",
|
|
438
|
+
"useCase": "**",
|
|
439
|
+
"inputSchema": "{\n operation: \"scrapePosts\" | \"searchPosts\" // Operation to perform: scrapePosts for user profiles, searchPosts for keyword search,\n username: string | undefined // LinkedIn username (for scrapePosts operation). Examples: \"satyanadella\", \"billgates\",\n keyword: string | undefined // Keyword or phrase to search for (for searchPosts operation). Examples: \"AI\", \"hiring\", \"n8n\",\n sortBy: \"relevance\" | \"date_posted\" | undefined // Sort results by relevance or date posted (for searchPosts operation, default: relevance),\n dateFilter: \"\" | \"past-24h\" | \"past-week\" | \"past-month\" | undefined // Filter posts by date range (for searchPosts operation, default: no filter),\n limit: number | undefined // Maximum number of posts to fetch (default: 50 for search, 100 for profiles),\n pageNumber: number | undefined // Page number for pagination (default: 1),\n credentials: Record<string, string> | undefined // Required credentials (auto-injected)\n}",
|
|
440
|
+
"outputSchema": "{\n operation: \"scrapePosts\" | \"searchPosts\" // Operation that was performed,\n posts: { urn: string | null, fullUrn: string | null, postedAt: { date: string | null, relative: string | null, timestamp: number | null } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null, lastName: string | null, headline: string | null, username: string | null, profileUrl: string | null, profilePicture: string | null } | null, stats: { totalReactions: number | null, like: number | null, support: number | null, love: number | null, insight: number | null, celebrate: number | null, funny: number | null, comments: number | null, reposts: number | null } | null, media: { type: string | null, url: string | null, thumbnail: string | null, images: { url: string | null, width: number | null, height: number | null }[] | null } | null, article: { url: string | null, title: string | null, subtitle: string | null, thumbnail: string | null } | null, document: { title: string | null, pageCount: number | null, url: string | null, thumbnail: string | null } | null, resharedPost: { urn: string | null, postedAt: { date: string | null, relative: string | null, timestamp: number | null } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null, lastName: string | null, headline: string | null, username: string | null, profileUrl: string | null, profilePicture: string | null } | null, stats: { totalReactions: number | null, like: number | null, support: number | null, love: number | null, insight: number | null, celebrate: number | null, funny: number | null, comments: number | null, reposts: number | null } | null, media: { type: string | null, url: string | null, thumbnail: string | null, images: { url: string | null, width: number | null, height: number | null }[] | null } | null } | null }[] // Array of LinkedIn posts,\n username: string | undefined // LinkedIn username that was scraped (only for scrapePosts operation),\n paginationToken: string | null | undefined // Token for fetching next page of results (only for scrapePosts operation),\n keyword: string | undefined // Search keyword that was used (only for searchPosts operation),\n totalResults: number | null | undefined // Total results available (only for searchPosts operation),\n hasNextPage: boolean | null | undefined // Whether there are more results (only for searchPosts operation),\n totalPosts: number // Total number of posts found,\n success: boolean // Whether the operation was successful,\n error: string // Error message if operation failed\n}",
|
|
441
|
+
"usageExample": "// Example usage of linkedin-tool bubble\nconst linkedinTool = new LinkedinToolBubble({\n operation: \"scrapePosts\" // options: \"scrapePosts\", \"searchPosts\", // Operation to perform: scrapePosts for user profiles, searchPosts for keyword search,\n username: \"example string\", // LinkedIn username (for scrapePosts operation). Examples: \"satyanadella\", \"billgates\",\n keyword: \"example string\", // Keyword or phrase to search for (for searchPosts operation). Examples: \"AI\", \"hiring\", \"n8n\",\n sortBy: \"relevance\" // options: \"relevance\", \"date_posted\", // Sort results by relevance or date posted (for searchPosts operation, default: relevance),\n dateFilter: \"\" // options: \"\", \"past-24h\", \"past-week\", \"past-month\", // Filter posts by date range (for searchPosts operation, default: no filter),\n limit: 50 // default, // Maximum number of posts to fetch (default: 50 for search, 100 for profiles),\n pageNumber: 1 // default, // Page number for pagination (default: 1),\n});\n\nconst result = await linkedinTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// operation: \"scrapePosts\" | \"searchPosts\" // Operation that was performed,\n// posts: { urn: string | null, fullUrn: string | null, postedAt: { date: string | null, relative: string | null, timestamp: number | null } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null, lastName: string | null, headline: string | null, username: string | null, profileUrl: string | null, profilePicture: string | null } | null, stats: { totalReactions: number | null, like: number | null, support: number | null, love: number | null, insight: number | null, celebrate: number | null, funny: number | null, comments: number | null, reposts: number | null } | null, media: { type: string | null, url: string | null, thumbnail: string | null, images: { url: string | null, width: number | null, height: number | null }[] | null } | null, article: { url: string | null, title: string | null, subtitle: string | null, thumbnail: string | null } | null, document: { title: string | null, pageCount: number | null, url: string | null, thumbnail: string | null } | null, resharedPost: { urn: string | null, postedAt: { date: string | null, relative: string | null, timestamp: number | null } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null, lastName: string | null, headline: string | null, username: string | null, profileUrl: string | null, profilePicture: string | null } | null, stats: { totalReactions: number | null, like: number | null, support: number | null, love: number | null, insight: number | null, celebrate: number | null, funny: number | null, comments: number | null, reposts: number | null } | null, media: { type: string | null, url: string | null, thumbnail: string | null, images: { url: string | null, width: number | null, height: number | null }[] | null } | null } | null }[] // Array of LinkedIn posts,\n// username: string | undefined // LinkedIn username that was scraped (only for scrapePosts operation),\n// paginationToken: string | null | undefined // Token for fetching next page of results (only for scrapePosts operation),\n// keyword: string | undefined // Search keyword that was used (only for searchPosts operation),\n// totalResults: number | null | undefined // Total results available (only for searchPosts operation),\n// hasNextPage: boolean | null | undefined // Whether there are more results (only for searchPosts operation),\n// totalPosts: number // Total number of posts found,\n// success: boolean // Whether the operation was successful,\n// error: string // Error message if operation failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
442
|
+
"requiredCredentials": [
|
|
443
|
+
"APIFY_CRED"
|
|
444
|
+
]
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "web-crawl-tool",
|
|
448
|
+
"alias": "crawl",
|
|
449
|
+
"type": "tool",
|
|
450
|
+
"shortDescription": "Multi-page web crawling tool for exploring entire websites and subdomains.",
|
|
451
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
452
|
+
"inputSchema": "{\n url: string // The root URL to crawl and extract content from,\n format: \"markdown\" // Output format for crawled content,\n onlyMainContent: boolean // Extract only main content, filtering out navigation/footers,\n maxPages: number | undefined // Maximum number of pages to crawl,\n crawlDepth: number | undefined // Maximum depth to crawl,\n includePaths: string[] | undefined // URL patterns to include in crawl (regex patterns), Example: [\"^/blog/.*$\", \"^/docs/.*$\"],\n excludePaths: string[] | undefined // URL patterns to exclude from crawl (regex patterns), [\"^/admin/.*$\", \"^/private/.*$\"],\n waitFor: number // Time to wait for dynamic content in milliseconds,\n credentials: Record<string, string> | undefined // Required credentials including FIRECRAWL_API_KEY\n}",
|
|
453
|
+
"outputSchema": "{\n url: string // The original URL that was crawled,\n success: boolean // Whether the crawl operation was successful,\n error: string // Error message if crawl failed,\n pages: { url: string, title: string | undefined, content: string, depth: number | undefined }[] // Array of crawled pages with content,\n totalPages: number // Total number of pages crawled,\n metadata: { loadTime: number | undefined, crawlDepth: number | undefined, maxPagesReached: boolean | undefined } | undefined // Additional metadata about the crawl operation\n}",
|
|
454
|
+
"usageExample": "// Example usage of web-crawl-tool bubble\nconst webCrawlTool = new WebCrawlToolBubble({\n url: \"example string\", // The root URL to crawl and extract content from,\n format: \"markdown\", // Output format for crawled content,\n onlyMainContent: true // default, // Extract only main content, filtering out navigation/footers,\n maxPages: 10 // default, // Maximum number of pages to crawl,\n crawlDepth: 2 // default, // Maximum depth to crawl,\n includePaths: [\"example string\"], // URL patterns to include in crawl (regex patterns), Example: [\"^/blog/.*$\", \"^/docs/.*$\"],\n excludePaths: [\"example string\"], // URL patterns to exclude from crawl (regex patterns), [\"^/admin/.*$\", \"^/private/.*$\"],\n waitFor: 3000 // default, // Time to wait for dynamic content in milliseconds,\n});\n\nconst result = await webCrawlTool.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// url: string // The original URL that was crawled,\n// success: boolean // Whether the crawl operation was successful,\n// error: string // Error message if crawl failed,\n// pages: { url: string, title: string | undefined, content: string, depth: number | undefined }[] // Array of crawled pages with content,\n// totalPages: number // Total number of pages crawled,\n// metadata: { loadTime: number | undefined, crawlDepth: number | undefined, maxPagesReached: boolean | undefined } | undefined // Additional metadata about the crawl operation\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
455
|
+
"requiredCredentials": [
|
|
456
|
+
"FIRECRAWL_API_KEY"
|
|
457
|
+
]
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"name": "bubbleflow-generator",
|
|
461
|
+
"alias": "generate-flow",
|
|
462
|
+
"type": "workflow",
|
|
463
|
+
"shortDescription": "Generate BubbleFlow code from natural language",
|
|
464
|
+
"useCase": "General purpose bubble for various workflow needs",
|
|
465
|
+
"inputSchema": "{\n prompt: string // Natural language description of the desired BubbleFlow,\n credentials: Record<string, string> | undefined // Credentials for AI agent operations\n}",
|
|
466
|
+
"outputSchema": "{\n generatedCode: string // The generated BubbleFlow TypeScript code,\n isValid: boolean // Whether the generated code is valid,\n success: boolean,\n error: string,\n toolCalls: unknown[] // The tool calls made by the AI agent,\n summary: string // High-level instructions for using the validated flow,\n inputsSchema: string // JSON Schema (string) representing the inputs of the flow\n}",
|
|
467
|
+
"usageExample": "// Example usage of bubbleflow-generator bubble\nconst bubbleflowGenerator = new BubbleflowGeneratorBubble({\n prompt: \"example string\", // Natural language description of the desired BubbleFlow,\n});\n\nconst result = await bubbleflowGenerator.action();\n\n// Always check success status before using data\nif (!result.success) {\n throw new Error(`${metadata.name} failed: ${result.error}`);\n}\n\n// outputSchema for result.data:\n// {\n// generatedCode: string // The generated BubbleFlow TypeScript code,\n// isValid: boolean // Whether the generated code is valid,\n// success: boolean,\n// error: string,\n// toolCalls: unknown[] // The tool calls made by the AI agent,\n// summary: string // High-level instructions for using the validated flow,\n// inputsSchema: string // JSON Schema (string) representing the inputs of the flow\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
|
|
468
|
+
"requiredCredentials": [
|
|
469
|
+
"GOOGLE_GEMINI_CRED",
|
|
470
|
+
"OPENROUTER_CRED"
|
|
471
|
+
]
|
|
472
|
+
}
|
|
473
|
+
]
|
|
474
|
+
}
|