@bubblelab/bubble-core 0.1.8 → 0.1.10

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.
Files changed (224) hide show
  1. package/dist/bubble-bundle.d.ts +333 -1438
  2. package/dist/bubble-factory.d.ts.map +1 -1
  3. package/dist/bubble-factory.js +64 -28
  4. package/dist/bubble-factory.js.map +1 -1
  5. package/dist/bubble-flow/bubble-flow-class.d.ts +17 -1
  6. package/dist/bubble-flow/bubble-flow-class.d.ts.map +1 -1
  7. package/dist/bubble-flow/bubble-flow-class.js +16 -0
  8. package/dist/bubble-flow/bubble-flow-class.js.map +1 -1
  9. package/dist/bubble-flow/sample/data-analyst-flow.d.ts +1 -1
  10. package/dist/bubble-flow/sample/data-analyst-flow.d.ts.map +1 -1
  11. package/dist/bubble-flow/sample/error-ts.d.ts +1 -1
  12. package/dist/bubble-flow/sample/error-ts.d.ts.map +1 -1
  13. package/dist/bubble-flow/sample/sanitytest.d.ts +1 -1
  14. package/dist/bubble-flow/sample/sanitytest.d.ts.map +1 -1
  15. package/dist/bubble-flow/sample/simple-webhook-2.d.ts +1 -1
  16. package/dist/bubble-flow/sample/simple-webhook-2.d.ts.map +1 -1
  17. package/dist/bubble-flow/sample/simple-webhook.d.ts +1 -1
  18. package/dist/bubble-flow/sample/simple-webhook.d.ts.map +1 -1
  19. package/dist/bubble-flow/sample/simplified-data-analysis.flow.d.ts +1 -1
  20. package/dist/bubble-flow/sample/simplified-data-analysis.flow.d.ts.map +1 -1
  21. package/dist/bubble-flow/sample/slack-v0.1.d.ts +1 -1
  22. package/dist/bubble-flow/sample/slack-v0.1.d.ts.map +1 -1
  23. package/dist/bubble-flow/sample/slackagenttest.d.ts +1 -1
  24. package/dist/bubble-flow/sample/slackagenttest.d.ts.map +1 -1
  25. package/dist/bubbles/service-bubble/ai-agent.d.ts +115 -97
  26. package/dist/bubbles/service-bubble/ai-agent.d.ts.map +1 -1
  27. package/dist/bubbles/service-bubble/ai-agent.js +276 -96
  28. package/dist/bubbles/service-bubble/ai-agent.js.map +1 -1
  29. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +805 -0
  30. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts.map +1 -0
  31. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.js +131 -0
  32. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.js.map +1 -0
  33. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +485 -0
  34. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts.map +1 -0
  35. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.js +176 -0
  36. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.js.map +1 -0
  37. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +302 -0
  38. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts.map +1 -0
  39. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.js +138 -0
  40. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.js.map +1 -0
  41. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +642 -0
  42. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts.map +1 -0
  43. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.js +123 -0
  44. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.js.map +1 -0
  45. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +184 -0
  46. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts.map +1 -0
  47. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.js +145 -0
  48. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.js.map +1 -0
  49. package/dist/bubbles/service-bubble/apify/actors/youtube-transcript-scraper.d.ts +52 -0
  50. package/dist/bubbles/service-bubble/apify/actors/youtube-transcript-scraper.d.ts.map +1 -0
  51. package/dist/bubbles/service-bubble/apify/actors/youtube-transcript-scraper.js +29 -0
  52. package/dist/bubbles/service-bubble/apify/actors/youtube-transcript-scraper.js.map +1 -0
  53. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +1999 -0
  54. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts.map +1 -0
  55. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js +54 -0
  56. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.js.map +1 -0
  57. package/dist/bubbles/service-bubble/apify/apify.d.ts +143 -0
  58. package/dist/bubbles/service-bubble/apify/apify.d.ts.map +1 -0
  59. package/dist/bubbles/service-bubble/apify/apify.js +276 -0
  60. package/dist/bubbles/service-bubble/apify/apify.js.map +1 -0
  61. package/dist/bubbles/service-bubble/apify/index.d.ts +6 -0
  62. package/dist/bubbles/service-bubble/apify/index.d.ts.map +1 -0
  63. package/dist/bubbles/service-bubble/apify/index.js +6 -0
  64. package/dist/bubbles/service-bubble/apify/index.js.map +1 -0
  65. package/dist/bubbles/service-bubble/apify/types.d.ts +7 -0
  66. package/dist/bubbles/service-bubble/apify/types.d.ts.map +1 -0
  67. package/dist/bubbles/service-bubble/apify/types.js +5 -0
  68. package/dist/bubbles/service-bubble/apify/types.js.map +1 -0
  69. package/dist/bubbles/service-bubble/gmail.d.ts +626 -132
  70. package/dist/bubbles/service-bubble/gmail.d.ts.map +1 -1
  71. package/dist/bubbles/service-bubble/gmail.js +435 -7
  72. package/dist/bubbles/service-bubble/gmail.js.map +1 -1
  73. package/dist/bubbles/service-bubble/google-calendar.d.ts +36 -36
  74. package/dist/bubbles/service-bubble/google-drive.d.ts +233 -4
  75. package/dist/bubbles/service-bubble/google-drive.d.ts.map +1 -1
  76. package/dist/bubbles/service-bubble/google-drive.js +65 -75
  77. package/dist/bubbles/service-bubble/google-drive.js.map +1 -1
  78. package/dist/bubbles/service-bubble/google-sheets.d.ts +52 -52
  79. package/dist/bubbles/service-bubble/hello-world.js +2 -2
  80. package/dist/bubbles/service-bubble/hello-world.js.map +1 -1
  81. package/dist/bubbles/service-bubble/http.d.ts +6 -6
  82. package/dist/bubbles/service-bubble/postgresql.d.ts +4 -4
  83. package/dist/bubbles/service-bubble/resend.d.ts +5 -5
  84. package/dist/bubbles/service-bubble/resend.d.ts.map +1 -1
  85. package/dist/bubbles/service-bubble/resend.js +16 -5
  86. package/dist/bubbles/service-bubble/resend.js.map +1 -1
  87. package/dist/bubbles/service-bubble/slack.d.ts +18 -18
  88. package/dist/bubbles/service-bubble/storage.d.ts +4 -4
  89. package/dist/bubbles/service-bubble/storage.d.ts.map +1 -1
  90. package/dist/bubbles/service-bubble/storage.js +16 -5
  91. package/dist/bubbles/service-bubble/storage.js.map +1 -1
  92. package/dist/bubbles/service-bubble/x-twitter.d.ts +814 -0
  93. package/dist/bubbles/service-bubble/x-twitter.d.ts.map +1 -0
  94. package/dist/bubbles/service-bubble/x-twitter.js +445 -0
  95. package/dist/bubbles/service-bubble/x-twitter.js.map +1 -0
  96. package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +20 -20
  97. package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +16 -16
  98. package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts +14 -1
  99. package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts.map +1 -1
  100. package/dist/bubbles/tool-bubble/get-bubble-details-tool.js +101 -47
  101. package/dist/bubbles/tool-bubble/get-bubble-details-tool.js.map +1 -1
  102. package/dist/bubbles/tool-bubble/instagram-tool.d.ts +435 -0
  103. package/dist/bubbles/tool-bubble/instagram-tool.d.ts.map +1 -0
  104. package/dist/bubbles/tool-bubble/instagram-tool.js +474 -0
  105. package/dist/bubbles/tool-bubble/instagram-tool.js.map +1 -0
  106. package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +2136 -0
  107. package/dist/bubbles/tool-bubble/linkedin-tool.d.ts.map +1 -0
  108. package/dist/bubbles/tool-bubble/linkedin-tool.js +608 -0
  109. package/dist/bubbles/tool-bubble/linkedin-tool.js.map +1 -0
  110. package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +69 -64
  111. package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts.map +1 -1
  112. package/dist/bubbles/tool-bubble/reddit-scrape-tool.js +97 -22
  113. package/dist/bubbles/tool-bubble/reddit-scrape-tool.js.map +1 -1
  114. package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +6 -6
  115. package/dist/bubbles/tool-bubble/research-agent-tool.js +5 -5
  116. package/dist/bubbles/tool-bubble/research-agent-tool.js.map +1 -1
  117. package/dist/bubbles/tool-bubble/tool-template.d.ts +8 -8
  118. package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts +14 -14
  119. package/dist/bubbles/tool-bubble/web-extract-tool.d.ts +4 -4
  120. package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts +28 -28
  121. package/dist/bubbles/tool-bubble/web-scrape-tool.js +1 -1
  122. package/dist/bubbles/tool-bubble/web-scrape-tool.js.map +1 -1
  123. package/dist/bubbles/tool-bubble/web-search-tool.d.ts +5 -4
  124. package/dist/bubbles/tool-bubble/web-search-tool.d.ts.map +1 -1
  125. package/dist/bubbles/tool-bubble/web-search-tool.js +6 -2
  126. package/dist/bubbles/tool-bubble/web-search-tool.js.map +1 -1
  127. package/dist/bubbles/tool-bubble/youtube-tool.d.ts +394 -0
  128. package/dist/bubbles/tool-bubble/youtube-tool.d.ts.map +1 -0
  129. package/dist/bubbles/tool-bubble/youtube-tool.js +352 -0
  130. package/dist/bubbles/tool-bubble/youtube-tool.js.map +1 -0
  131. package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts +47 -36
  132. package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts.map +1 -1
  133. package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js +96 -65
  134. package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js.map +1 -1
  135. package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +38 -38
  136. package/dist/bubbles/workflow-bubble/generate-document.workflow.js +1 -1
  137. package/dist/bubbles/workflow-bubble/generate-document.workflow.js.map +1 -1
  138. package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +42 -42
  139. package/dist/bubbles/workflow-bubble/parse-document.workflow.js +1 -1
  140. package/dist/bubbles/workflow-bubble/parse-document.workflow.js.map +1 -1
  141. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +22 -22
  142. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts.map +1 -1
  143. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js +1 -4
  144. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.js.map +1 -1
  145. package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +60 -60
  146. package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts.map +1 -1
  147. package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.js +2 -2
  148. package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.js.map +1 -1
  149. package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +20 -20
  150. package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js +1 -1
  151. package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.js.map +1 -1
  152. package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +66 -66
  153. package/dist/bubbles/workflow-bubble/slack-formatter-agent.js +1 -1
  154. package/dist/bubbles/workflow-bubble/slack-formatter-agent.js.map +1 -1
  155. package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +18 -18
  156. package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts.map +1 -1
  157. package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js +1 -2
  158. package/dist/bubbles/workflow-bubble/slack-notifier.workflow.js.map +1 -1
  159. package/dist/bubbles.json +489 -0
  160. package/dist/index.d.ts +16 -3
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +8 -1
  163. package/dist/index.js.map +1 -1
  164. package/dist/logging/BubbleLogger.d.ts +11 -0
  165. package/dist/logging/BubbleLogger.d.ts.map +1 -1
  166. package/dist/logging/BubbleLogger.js +87 -33
  167. package/dist/logging/BubbleLogger.js.map +1 -1
  168. package/dist/logging/StreamingBubbleLogger.d.ts.map +1 -1
  169. package/dist/logging/StreamingBubbleLogger.js +23 -16
  170. package/dist/logging/StreamingBubbleLogger.js.map +1 -1
  171. package/dist/test-gm.d.ts +10 -0
  172. package/dist/test-gm.d.ts.map +1 -0
  173. package/dist/test-gm.js +95 -0
  174. package/dist/test-gm.js.map +1 -0
  175. package/dist/types/available-tools.d.ts +1 -1
  176. package/dist/types/available-tools.d.ts.map +1 -1
  177. package/dist/types/available-tools.js +2 -0
  178. package/dist/types/available-tools.js.map +1 -1
  179. package/dist/types/base-bubble-class.d.ts +6 -1
  180. package/dist/types/base-bubble-class.d.ts.map +1 -1
  181. package/dist/types/base-bubble-class.js +47 -24
  182. package/dist/types/base-bubble-class.js.map +1 -1
  183. package/dist/types/bubble.d.ts +3 -13
  184. package/dist/types/bubble.d.ts.map +1 -1
  185. package/dist/types/bubble.js +1 -1
  186. package/dist/types/bubble.js.map +1 -1
  187. package/dist/types/service-bubble-class.d.ts +5 -5
  188. package/dist/types/service-bubble-class.d.ts.map +1 -1
  189. package/dist/types/service-bubble-class.js +6 -7
  190. package/dist/types/service-bubble-class.js.map +1 -1
  191. package/dist/types/tool-bubble-class.d.ts +1 -1
  192. package/dist/types/tool-bubble-class.d.ts.map +1 -1
  193. package/dist/types/tool-bubble-class.js +9 -3
  194. package/dist/types/tool-bubble-class.js.map +1 -1
  195. package/dist/types/workflow-bubble-class.d.ts +1 -1
  196. package/dist/types/workflow-bubble-class.d.ts.map +1 -1
  197. package/dist/utils/agent-formatter.d.ts +17 -0
  198. package/dist/utils/agent-formatter.d.ts.map +1 -0
  199. package/dist/utils/agent-formatter.js +139 -0
  200. package/dist/utils/agent-formatter.js.map +1 -0
  201. package/dist/utils/bubbleflow-validation.d.ts.map +1 -1
  202. package/dist/utils/bubbleflow-validation.js +89 -32
  203. package/dist/utils/bubbleflow-validation.js.map +1 -1
  204. package/dist/utils/error-sanitizer.d.ts +12 -0
  205. package/dist/utils/error-sanitizer.d.ts.map +1 -0
  206. package/dist/utils/error-sanitizer.js +77 -0
  207. package/dist/utils/error-sanitizer.js.map +1 -0
  208. package/dist/utils/json-parsing.d.ts +1 -0
  209. package/dist/utils/json-parsing.d.ts.map +1 -1
  210. package/dist/utils/json-parsing.js +205 -32
  211. package/dist/utils/json-parsing.js.map +1 -1
  212. package/package.json +6 -5
  213. package/dist/bubble-trigger/index.d.ts +0 -2
  214. package/dist/bubble-trigger/index.d.ts.map +0 -1
  215. package/dist/bubble-trigger/index.js +0 -2
  216. package/dist/bubble-trigger/index.js.map +0 -1
  217. package/dist/bubble-trigger/types.d.ts +0 -87
  218. package/dist/bubble-trigger/types.d.ts.map +0 -1
  219. package/dist/bubble-trigger/types.js +0 -14
  220. package/dist/bubble-trigger/types.js.map +0 -1
  221. package/dist/types/ai-models.d.ts +0 -4
  222. package/dist/types/ai-models.d.ts.map +0 -1
  223. package/dist/types/ai-models.js +0 -16
  224. package/dist/types/ai-models.js.map +0 -1
@@ -0,0 +1,489 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "generatedAt": "2025-11-02T09:38:25.586Z",
4
+ "totalCount": 36,
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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" // AI model to use (format: provider/model-name)., temperature: number // Temperature for response randomness (0 = deterministic, 2 = very random), maxTokens: number | undefined // Maximum number of tokens to generate in response, keep at default of 40000 unless the response is expected to be certain length, jsonMode: boolean // When true, strips markdown formatting and returns clean JSON response } // 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\" // Name of the tool type or tool bubble to enable for the AI agent, credentials: Record<string, string> | undefined // Credential types to use for the tool bubble (injected at runtime), config: Record<string, unknown> | undefined // Configuration for the tool or tool bubble }[] // 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 // Unique name for your custom tool (e.g., \"calculate-tax\"), description: string // Description of what the tool does - helps the AI know when to use it, schema: Record<string, unknown> // Zod schema object defining the tool parameters. Example: { amount: z.number().describe(\"Amount to calculate tax on\"), rate: z.number().describe(\"Tax rate\") }, func: unknown // Async function that executes the tool logic. Receives params matching the schema and returns a result. }[] | 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 // Name of the tool that was called, input: unknown // Input parameters passed to the tool, output: unknown // Output returned by the tool }[] // 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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: 12800 // 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 // Name of the tool that was called, input: unknown // Input parameters passed to the tool, output: unknown // Output returned by the tool }[] // 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 // Column name, dataTypeID: number // PostgreSQL data type identifier }[] | 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 // Column name, dataTypeID: number // PostgreSQL data type identifier }[] | 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 // Message type (usually \"message\"), ts: string // Message timestamp (unique identifier), user: string | undefined // User ID who sent the message, bot_id: string | undefined // Bot ID if message was sent by a bot, bot_profile: { name: string | undefined // Bot display name } | undefined // Bot profile information if message was sent by a bot, username: string | undefined // Username of the bot or user who sent the message, text: string | undefined // Message text content, thread_ts: string | undefined // Timestamp of parent message if this is a thread reply, parent_user_id: string | undefined // User ID of thread parent message author, reply_count: number | undefined // Number of replies in this thread, reply_users_count: number | undefined // Number of unique users who replied in thread, latest_reply: string | undefined // Timestamp of most recent reply in thread, reply_users: string[] | undefined // Array of user IDs who replied in thread, is_locked: boolean | undefined // True if thread is locked, subscribed: boolean | undefined // True if current user is subscribed to thread, attachments: unknown[] | undefined // Legacy message attachments, blocks: unknown[] | undefined // Block Kit structured content, reactions: { name: string // Emoji name without colons, users: string[] // User IDs who reacted with this emoji, count: number // Total count of this reaction }[] | undefined // Array of emoji reactions on this message } | 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 // Unique channel identifier, name: string // Channel name without # prefix, is_channel: boolean | undefined // True if this is a public channel, is_group: boolean | undefined // True if this is a private channel, is_im: boolean | undefined // True if this is a direct message, is_mpim: boolean | undefined // True if this is a multi-person direct message, is_private: boolean | undefined // True if this is a private channel, created: number // Unix timestamp when channel was created, is_archived: boolean // True if channel is archived, is_general: boolean | undefined // True if this is the #general channel, unlinked: number | undefined // Unix timestamp when channel was unlinked, name_normalized: string | undefined // Normalized channel name, is_shared: boolean | undefined // True if channel is shared with other workspaces, is_ext_shared: boolean | undefined // True if channel is shared externally, is_org_shared: boolean | undefined // True if channel is shared across organization, shared_team_ids: string[] | undefined // IDs of teams this channel is shared with, pending_shared: string[] | undefined // Pending shared connections, pending_connected_team_ids: string[] | undefined // Pending team connection IDs, is_pending_ext_shared: boolean | undefined // True if external sharing is pending, is_member: boolean | undefined // True if the bot is a member of this channel, is_open: boolean | undefined // True if the channel is open, topic: { value: string // Topic text, creator: string // User ID who set the topic, last_set: number // Unix timestamp when topic was last set } | undefined // Channel topic information, purpose: { value: string // Purpose text, creator: string // User ID who set the purpose, last_set: number // Unix timestamp when purpose was last set } | undefined // Channel purpose information, num_members: number | undefined // Number of members in the channel }[] | undefined // Array of channel objects,\n// response_metadata: { next_cursor: string // Cursor for pagination to get next set of results } | 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 // Unique channel identifier, name: string // Channel name without # prefix, is_channel: boolean | undefined // True if this is a public channel, is_group: boolean | undefined // True if this is a private channel, is_im: boolean | undefined // True if this is a direct message, is_mpim: boolean | undefined // True if this is a multi-person direct message, is_private: boolean | undefined // True if this is a private channel, created: number // Unix timestamp when channel was created, is_archived: boolean // True if channel is archived, is_general: boolean | undefined // True if this is the #general channel, unlinked: number | undefined // Unix timestamp when channel was unlinked, name_normalized: string | undefined // Normalized channel name, is_shared: boolean | undefined // True if channel is shared with other workspaces, is_ext_shared: boolean | undefined // True if channel is shared externally, is_org_shared: boolean | undefined // True if channel is shared across organization, shared_team_ids: string[] | undefined // IDs of teams this channel is shared with, pending_shared: string[] | undefined // Pending shared connections, pending_connected_team_ids: string[] | undefined // Pending team connection IDs, is_pending_ext_shared: boolean | undefined // True if external sharing is pending, is_member: boolean | undefined // True if the bot is a member of this channel, is_open: boolean | undefined // True if the channel is open, topic: { value: string // Topic text, creator: string // User ID who set the topic, last_set: number // Unix timestamp when topic was last set } | undefined // Channel topic information, purpose: { value: string // Purpose text, creator: string // User ID who set the purpose, last_set: number // Unix timestamp when purpose was last set } | undefined // Channel purpose information, num_members: number | undefined // Number of members in the channel } | 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 // Unique user identifier, team_id: string | undefined // Team/workspace ID, name: string // Username (handle without @), deleted: boolean | undefined // True if user account is deleted, color: string | undefined // Color code for user in UI, real_name: string | undefined // Users real name, tz: string | undefined // Timezone identifier, tz_label: string | undefined // Human-readable timezone label, tz_offset: number | undefined // Timezone offset from UTC in seconds, profile: { title: string | undefined // Job title, phone: string | undefined // Phone number, skype: string | undefined // Skype username, real_name: string | undefined // Real name from profile, real_name_normalized: string | undefined // Normalized real name, display_name: string | undefined // Display name, display_name_normalized: string | undefined // Normalized display name, fields: Record<string, unknown> | undefined // Custom profile fields, status_text: string | undefined // Current status text, status_emoji: string | undefined // Current status emoji, status_expiration: number | undefined // Unix timestamp when status expires, avatar_hash: string | undefined // Hash for avatar image, image_original: string | undefined // URL of original avatar image, is_custom_image: boolean | undefined // True if using custom avatar, email: string | undefined // Email address, first_name: string | undefined // First name, last_name: string | undefined // Last name, image_24: string | undefined // 24x24 pixel avatar URL, image_32: string | undefined // 32x32 pixel avatar URL, image_48: string | undefined // 48x48 pixel avatar URL, image_72: string | undefined // 72x72 pixel avatar URL, image_192: string | undefined // 192x192 pixel avatar URL, image_512: string | undefined // 512x512 pixel avatar URL, image_1024: string | undefined // 1024x1024 pixel avatar URL } | undefined // User profile information, is_admin: boolean | undefined // True if user is workspace admin, is_owner: boolean | undefined // True if user is workspace owner, is_primary_owner: boolean | undefined // True if user is primary workspace owner, is_restricted: boolean | undefined // True if user is restricted (single-channel guest), is_ultra_restricted: boolean | undefined // True if user is ultra restricted (multi-channel guest), is_bot: boolean | undefined // True if this is a bot user, is_app_user: boolean | undefined // True if this is an app user, updated: number | undefined // Unix timestamp when user was last updated, has_2fa: boolean | undefined // True if user has two-factor authentication enabled } | 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 // Unique user identifier, team_id: string | undefined // Team/workspace ID, name: string // Username (handle without @), deleted: boolean | undefined // True if user account is deleted, color: string | undefined // Color code for user in UI, real_name: string | undefined // Users real name, tz: string | undefined // Timezone identifier, tz_label: string | undefined // Human-readable timezone label, tz_offset: number | undefined // Timezone offset from UTC in seconds, profile: { title: string | undefined // Job title, phone: string | undefined // Phone number, skype: string | undefined // Skype username, real_name: string | undefined // Real name from profile, real_name_normalized: string | undefined // Normalized real name, display_name: string | undefined // Display name, display_name_normalized: string | undefined // Normalized display name, fields: Record<string, unknown> | undefined // Custom profile fields, status_text: string | undefined // Current status text, status_emoji: string | undefined // Current status emoji, status_expiration: number | undefined // Unix timestamp when status expires, avatar_hash: string | undefined // Hash for avatar image, image_original: string | undefined // URL of original avatar image, is_custom_image: boolean | undefined // True if using custom avatar, email: string | undefined // Email address, first_name: string | undefined // First name, last_name: string | undefined // Last name, image_24: string | undefined // 24x24 pixel avatar URL, image_32: string | undefined // 32x32 pixel avatar URL, image_48: string | undefined // 48x48 pixel avatar URL, image_72: string | undefined // 72x72 pixel avatar URL, image_192: string | undefined // 192x192 pixel avatar URL, image_512: string | undefined // 512x512 pixel avatar URL, image_1024: string | undefined // 1024x1024 pixel avatar URL } | undefined // User profile information, is_admin: boolean | undefined // True if user is workspace admin, is_owner: boolean | undefined // True if user is workspace owner, is_primary_owner: boolean | undefined // True if user is primary workspace owner, is_restricted: boolean | undefined // True if user is restricted (single-channel guest), is_ultra_restricted: boolean | undefined // True if user is ultra restricted (multi-channel guest), is_bot: boolean | undefined // True if this is a bot user, is_app_user: boolean | undefined // True if this is an app user, updated: number | undefined // Unix timestamp when user was last updated, has_2fa: boolean | undefined // True if user has two-factor authentication enabled }[] | undefined // Array of user objects,\n// response_metadata: { next_cursor: string // Cursor for pagination to get next set of results } | 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 // Message type (usually \"message\"), ts: string // Message timestamp (unique identifier), user: string | undefined // User ID who sent the message, bot_id: string | undefined // Bot ID if message was sent by a bot, bot_profile: { name: string | undefined // Bot display name } | undefined // Bot profile information if message was sent by a bot, username: string | undefined // Username of the bot or user who sent the message, text: string | undefined // Message text content, thread_ts: string | undefined // Timestamp of parent message if this is a thread reply, parent_user_id: string | undefined // User ID of thread parent message author, reply_count: number | undefined // Number of replies in this thread, reply_users_count: number | undefined // Number of unique users who replied in thread, latest_reply: string | undefined // Timestamp of most recent reply in thread, reply_users: string[] | undefined // Array of user IDs who replied in thread, is_locked: boolean | undefined // True if thread is locked, subscribed: boolean | undefined // True if current user is subscribed to thread, attachments: unknown[] | undefined // Legacy message attachments, blocks: unknown[] | undefined // Block Kit structured content, reactions: { name: string // Emoji name without colons, users: string[] // User IDs who reacted with this emoji, count: number // Total count of this reaction }[] | undefined // Array of emoji reactions on this message }[] | undefined // Array of message objects,\n// has_more: boolean | undefined // Whether there are more messages to retrieve,\n// response_metadata: { next_cursor: string // Cursor for pagination to get next set of results } | 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 // Message type (usually \"message\"), ts: string // Message timestamp (unique identifier), user: string | undefined // User ID who sent the message, bot_id: string | undefined // Bot ID if message was sent by a bot, bot_profile: { name: string | undefined // Bot display name } | undefined // Bot profile information if message was sent by a bot, username: string | undefined // Username of the bot or user who sent the message, text: string | undefined // Message text content, thread_ts: string | undefined // Timestamp of parent message if this is a thread reply, parent_user_id: string | undefined // User ID of thread parent message author, reply_count: number | undefined // Number of replies in this thread, reply_users_count: number | undefined // Number of unique users who replied in thread, latest_reply: string | undefined // Timestamp of most recent reply in thread, reply_users: string[] | undefined // Array of user IDs who replied in thread, is_locked: boolean | undefined // True if thread is locked, subscribed: boolean | undefined // True if current user is subscribed to thread, attachments: unknown[] | undefined // Legacy message attachments, blocks: unknown[] | undefined // Block Kit structured content, reactions: { name: string // Emoji name without colons, users: string[] // User IDs who reacted with this emoji, count: number // Total count of this reaction }[] | undefined // Array of emoji reactions on this message }[] | 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 // Cursor for pagination to get next set of results } | 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 // Message type (usually \"message\"), ts: string // Message timestamp (unique identifier), user: string | undefined // User ID who sent the message, bot_id: string | undefined // Bot ID if message was sent by a bot, bot_profile: { name: string | undefined // Bot display name } | undefined // Bot profile information if message was sent by a bot, username: string | undefined // Username of the bot or user who sent the message, text: string | undefined // Message text content, thread_ts: string | undefined // Timestamp of parent message if this is a thread reply, parent_user_id: string | undefined // User ID of thread parent message author, reply_count: number | undefined // Number of replies in this thread, reply_users_count: number | undefined // Number of unique users who replied in thread, latest_reply: string | undefined // Timestamp of most recent reply in thread, reply_users: string[] | undefined // Array of user IDs who replied in thread, is_locked: boolean | undefined // True if thread is locked, subscribed: boolean | undefined // True if current user is subscribed to thread, attachments: unknown[] | undefined // Legacy message attachments, blocks: unknown[] | undefined // Block Kit structured content, reactions: { name: string // Emoji name without colons, users: string[] // User IDs who reacted with this emoji, count: number // Total count of this reaction }[] | undefined // Array of emoji reactions on this message } | 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 // Unique file identifier, created: number // Unix timestamp when file was created, timestamp: number // Unix timestamp when file was uploaded, name: string // Original filename, title: string | undefined // File title, mimetype: string // MIME type of the file, filetype: string // File type extension, pretty_type: string // Human-readable file type, user: string // User ID who uploaded the file, editable: boolean // Whether the file is editable, size: number // File size in bytes, mode: string // File sharing mode, is_external: boolean // Whether file is from external source, external_type: string // External file type if applicable, is_public: boolean // Whether file is publicly accessible, public_url_shared: boolean // Whether public URL is shared, display_as_bot: boolean // Whether file is displayed as uploaded by bot, username: string // Username of uploader, url_private: string // Private URL to access file, url_private_download: string // Private download URL, permalink: string // Permanent link to file, permalink_public: string | undefined // Public permanent link, shares: { public: Record<string, { reply_users: string[] // User IDs who replied, reply_users_count: number // Number of unique users who replied, reply_count: number // Total number of replies, ts: string // Timestamp of the share, channel_name: string // Name of the channel, team_id: string // Team ID }[]> | undefined // Public channel shares, private: Record<string, { reply_users: string[] // User IDs who replied, reply_users_count: number // Number of unique users who replied, reply_count: number // Total number of replies, ts: string // Timestamp of the share, channel_name: string // Name of the channel, team_id: string // Team ID }[]> | undefined // Private channel shares } | undefined // Information about where file is shared, channels: string[] | undefined // Channel IDs where file is shared, groups: string[] | undefined // Private group IDs where file is shared, ims: string[] | undefined // Direct message IDs where file is shared, has_rich_preview: boolean | undefined // Whether file has rich preview } | 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: \"bubble-lab-bucket\" // default,\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 and generate a new secure filename for the file,\n// success: boolean // Whether the operation was successful,\n// fileName: string | undefined // Secure filename for the updated file (different from the original filename),\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 // Page number (1-indexed), uploadUrl: string // Presigned upload URL for this page, fileName: string // Secure filename for this page image }[] | 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 // Unique file identifier, name: string // Name of the file, mimeType: string // MIME type of the file, size: string | undefined // Size of the file in bytes, createdTime: string | undefined // Creation time in RFC 3339 format, modifiedTime: string | undefined // Last modified time in RFC 3339 format, webViewLink: string | undefined // Link to view the file in Google Drive, webContentLink: string | undefined // Link to download the file, parents: string[] | undefined // Parent folder IDs, shared: boolean | undefined // Whether the file is shared, owners: { displayName: string | undefined // Owner display name, emailAddress: string | undefined // Owner email address }[] | undefined // File owners } | 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 // Unique file identifier, name: string // Name of the file, mimeType: string // MIME type of the file, size: string | undefined // Size of the file in bytes, createdTime: string | undefined // Creation time in RFC 3339 format, modifiedTime: string | undefined // Last modified time in RFC 3339 format, webViewLink: string | undefined // Link to view the file in Google Drive, webContentLink: string | undefined // Link to download the file, parents: string[] | undefined // Parent folder IDs, shared: boolean | undefined // Whether the file is shared, owners: { displayName: string | undefined // Owner display name, emailAddress: string | undefined // Owner email address }[] | undefined // File owners }[] | 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 // Unique folder identifier, name: string // Name of the folder, webViewLink: string | undefined // Link to view the folder in Google Drive, parents: string[] | undefined // Parent folder IDs } | 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 // Unique file identifier, name: string // Name of the file, mimeType: string // MIME type of the file, size: string | undefined // Size of the file in bytes, createdTime: string | undefined // Creation time in RFC 3339 format, modifiedTime: string | undefined // Last modified time in RFC 3339 format, webViewLink: string | undefined // Link to view the file in Google Drive, webContentLink: string | undefined // Link to download the file, parents: string[] | undefined // Parent folder IDs, shared: boolean | undefined // Whether the file is shared, owners: { displayName: string | undefined // Owner display name, emailAddress: string | undefined // Owner email address }[] | undefined // File owners } | undefined // File metadata and information,\n// permissions: { id: string, type: string, role: string, emailAddress: string | undefined // Permission holder email address, displayName: string | undefined // Permission holder display name }[] | 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// Move File example\nconst googleDrive_move_file = new GoogleDriveBubble({\n operation: \"move_file\", // Move a file or folder to a different location in Google Drive\n file_id: \"example string\", // Google Drive file or folder ID to move\n new_parent_folder_id: \"example string\", // ID of the new parent folder (moves to root if not provided)\n remove_parent_folder_id: \"example string\", // ID of the parent folder to remove (removes from all parents if not provided)\n});\n\nconst result = await googleDrive_move_file.action();\n// outputSchema for result.data when operation === 'move_file':\n// {\n// operation: \"move_file\" // Move a file or folder to a different location in Google Drive,\n// success: boolean // Whether the file was moved successfully,\n// file: { id: string // Unique file identifier, name: string // Name of the file, mimeType: string // MIME type of the file, size: string | undefined // Size of the file in bytes, createdTime: string | undefined // Creation time in RFC 3339 format, modifiedTime: string | undefined // Last modified time in RFC 3339 format, webViewLink: string | undefined // Link to view the file in Google Drive, webContentLink: string | undefined // Link to download the file, parents: string[] | undefined // Parent folder IDs, shared: boolean | undefined // Whether the file is shared, owners: { displayName: string | undefined // Owner display name, emailAddress: string | undefined // Owner email address }[] | undefined // File owners } | undefined // Updated file metadata after move,\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 include_details: true // default, // Whether to fetch full message details including snippet, headers, and body\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 // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure }[] | 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 // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure } | 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 // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure }[] | 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 // Unique draft identifier, message: { id: string // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure } // Draft message content } | 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 // Unique draft identifier, message: { id: string // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure } // Draft message content }[] | 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 // Unique thread identifier, historyId: string | undefined // Last history record ID, messages: { id: string // Unique message identifier, threadId: string | undefined // Thread identifier this message belongs to, labelIds: string[] | undefined // List of label IDs applied to this message, snippet: string | undefined // Short snippet of the message text, textContent: string | undefined // Clean, readable email text content, historyId: string | undefined // History record ID that last modified this message, internalDate: string | undefined // Internal message creation timestamp (epoch ms), sizeEstimate: number | undefined // Estimated size in bytes, raw: string | undefined // Entire email message in RFC 2822 format (base64url encoded), payload: { mimeType: string | undefined // MIME type of the email content, headers: { name: string // Header name (e.g., \"Subject\", \"From\", \"To\"), value: string // Header value }[] | undefined // Essential email headers only (Subject, From, To, Cc, Bcc, Date, Reply-To, Message-ID, In-Reply-To, References), body: { data: string | undefined // Email body content (base64url encoded), size: number | undefined // Size of the body content in bytes, attachmentId: string | undefined // ID of the attachment if this body part is an attachment } | undefined // Email body content and metadata, parts: unknown[] | undefined // Array of message parts for multipart emails } | undefined // Parsed email structure }[] | undefined // Messages in this thread, snippet: string | undefined // Thread snippet }[] | 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// List Labels example\nconst gmail_list_labels = new GmailBubble({\n operation: \"list_labels\", // List all labels in mailbox\n});\n\nconst result = await gmail_list_labels.action();\n// outputSchema for result.data when operation === 'list_labels':\n// {\n// operation: \"list_labels\" // List all labels in mailbox,\n// success: boolean // Whether the label list was retrieved successfully,\n// labels: { id: string // Label ID, name: string // Label name, type: \"system\" | \"user\" | undefined // Label type: system (built-in) or user (custom), messageListVisibility: \"show\" | \"hide\" | undefined // Visibility in message list, labelListVisibility: \"labelShow\" | \"labelShowIfUnread\" | \"labelHide\" | undefined // Visibility in label list }[] | undefined // List of labels (both system and user labels),\n// error: string // Error message if operation failed\n// }\n\n\n// Create Label example\nconst gmail_create_label = new GmailBubble({\n operation: \"create_label\", // Create a new custom label\n name: \"example string\", // Label name (display name)\n label_list_visibility: \"labelShow\" // options: \"labelShow\", \"labelShowIfUnread\", \"labelHide\", // Visibility in label list\n message_list_visibility: \"show\" // options: \"show\", \"hide\", // Visibility in message list\n background_color: \"example string\", // Background color in hex format (e.g., #000000)\n text_color: \"example string\", // Text color in hex format (e.g., #ffffff)\n});\n\nconst result = await gmail_create_label.action();\n// outputSchema for result.data when operation === 'create_label':\n// {\n// operation: \"create_label\" // Create a new custom label,\n// success: boolean // Whether the label was created successfully,\n// label: { id: string // Label ID, name: string // Label name, type: \"system\" | \"user\" | undefined // Label type: system (built-in) or user (custom), messageListVisibility: \"show\" | \"hide\" | undefined // Visibility in message list, labelListVisibility: \"labelShow\" | \"labelShowIfUnread\" | \"labelHide\" | undefined // Visibility in label list } | undefined // Created label details,\n// error: string // Error message if operation failed\n// }\n\n\n// Modify Message Labels example\nconst gmail_modify_message_labels = new GmailBubble({\n operation: \"modify_message_labels\", // Add or remove labels from a message\n message_id: \"example string\", // Gmail message ID to modify\n add_label_ids: [\"example string\"], // List of label IDs to add (max 100)\n remove_label_ids: [\"example string\"], // List of label IDs to remove (max 100)\n});\n\nconst result = await gmail_modify_message_labels.action();\n// outputSchema for result.data when operation === 'modify_message_labels':\n// {\n// operation: \"modify_message_labels\" // Add or remove labels from a message,\n// success: boolean // Whether the labels were modified successfully,\n// message_id: string | undefined // Modified message ID,\n// label_ids: string[] | undefined // Current label IDs after modification,\n// error: string // Error message if operation failed\n// }\n\n\n// Modify Thread Labels example\nconst gmail_modify_thread_labels = new GmailBubble({\n operation: \"modify_thread_labels\", // Add or remove labels from all messages in a thread\n thread_id: \"example string\", // Gmail thread ID to modify\n add_label_ids: [\"example string\"], // List of label IDs to add to all messages in thread (max 100)\n remove_label_ids: [\"example string\"], // List of label IDs to remove from all messages in thread (max 100)\n});\n\nconst result = await gmail_modify_thread_labels.action();\n// outputSchema for result.data when operation === 'modify_thread_labels':\n// {\n// operation: \"modify_thread_labels\" // Add or remove labels from all messages in a thread,\n// success: boolean // Whether the thread labels were modified successfully,\n// thread_id: string | undefined // Modified thread ID,\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 // The A1 notation range, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined // Major dimension of the values, values: unknown[][] // The data values as array of arrays } | 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 // The A1 notation range, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined // Major dimension of the values, values: unknown[][] // The data values as array of arrays } | 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 // The A1 notation range, majorDimension: \"ROWS\" | \"COLUMNS\" | undefined // Major dimension of the values, values: unknown[][] // The data values as array of arrays }[] | 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 // Range that was updated, updated_rows: number | undefined // Number of rows updated in this range, updated_columns: number | undefined // Number of columns updated in this range, updated_cells: number | undefined // Number of cells updated in this range }[] | 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 // Unique spreadsheet identifier, properties: { title: string // Spreadsheet title, locale: string | undefined // Spreadsheet locale, autoRecalc: string | undefined // Auto recalc setting, timeZone: string | undefined // Time zone } | undefined // Spreadsheet properties, sheets: { properties: { sheetId: number // Sheet ID, title: string // Sheet title, index: number // Sheet index, sheetType: string | undefined // Sheet type, gridProperties: { rowCount: number | undefined // Number of rows in the sheet, columnCount: number | undefined // Number of columns in the sheet } | undefined // Grid properties of the sheet } // Sheet properties }[] | undefined // List of sheets in the spreadsheet, spreadsheetUrl: string | undefined // URL to the spreadsheet } | 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 // Unique spreadsheet identifier, properties: { title: string // Spreadsheet title, locale: string | undefined // Spreadsheet locale, autoRecalc: string | undefined // Auto recalc setting, timeZone: string | undefined // Time zone } | undefined // Spreadsheet properties, sheets: { properties: { sheetId: number // Sheet ID, title: string // Sheet title, index: number // Sheet index, sheetType: string | undefined // Sheet type, gridProperties: { rowCount: number | undefined // Number of rows in the sheet, columnCount: number | undefined // Number of columns in the sheet } | undefined // Grid properties of the sheet } // Sheet properties }[] | undefined // List of sheets in the spreadsheet, spreadsheetUrl: string | undefined // URL to the spreadsheet } | 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 // Calendar ID, summary: string | undefined // Calendar title, description: string | undefined // Calendar description, timeZone: string | undefined // Calendar time zone, selected: boolean | undefined // Whether this calendar is selected, accessRole: \"freeBusyReader\" | \"reader\" | \"writer\" | \"owner\" | undefined // Access role for the user }[] | 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 // Event ID, status: string | undefined // Event status (confirmed, tentative, cancelled), htmlLink: string | undefined // Link to the event in Calendar UI, created: string | undefined // Event creation timestamp, updated: string | undefined // Event last updated timestamp, summary: string | undefined // Event title, description: string | undefined // Event description, location: string | undefined // Event location, start: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event start date/time, end: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event end date/time, attendees: { email: string // Attendee email, optional: boolean | undefined // Whether this attendee is optional, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined // Response status of the attendee, displayName: string | undefined // Display name of the attendee }[] | undefined // List of event attendees, organizer: { email: string | undefined // Organizer email address, displayName: string | undefined // Organizer display name } | undefined // Event organizer information, hangoutLink: string | undefined // Google Hangout/Meet link for the event, conferenceData: unknown | undefined // Conference data for virtual meetings }[] | 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 // Event ID, status: string | undefined // Event status (confirmed, tentative, cancelled), htmlLink: string | undefined // Link to the event in Calendar UI, created: string | undefined // Event creation timestamp, updated: string | undefined // Event last updated timestamp, summary: string | undefined // Event title, description: string | undefined // Event description, location: string | undefined // Event location, start: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event start date/time, end: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event end date/time, attendees: { email: string // Attendee email, optional: boolean | undefined // Whether this attendee is optional, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined // Response status of the attendee, displayName: string | undefined // Display name of the attendee }[] | undefined // List of event attendees, organizer: { email: string | undefined // Organizer email address, displayName: string | undefined // Organizer display name } | undefined // Event organizer information, hangoutLink: string | undefined // Google Hangout/Meet link for the event, conferenceData: unknown | undefined // Conference data for virtual meetings } | 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 // Event ID, status: string | undefined // Event status (confirmed, tentative, cancelled), htmlLink: string | undefined // Link to the event in Calendar UI, created: string | undefined // Event creation timestamp, updated: string | undefined // Event last updated timestamp, summary: string | undefined // Event title, description: string | undefined // Event description, location: string | undefined // Event location, start: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event start date/time, end: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event end date/time, attendees: { email: string // Attendee email, optional: boolean | undefined // Whether this attendee is optional, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined // Response status of the attendee, displayName: string | undefined // Display name of the attendee }[] | undefined // List of event attendees, organizer: { email: string | undefined // Organizer email address, displayName: string | undefined // Organizer display name } | undefined // Event organizer information, hangoutLink: string | undefined // Google Hangout/Meet link for the event, conferenceData: unknown | undefined // Conference data for virtual meetings } | 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 // Event ID, status: string | undefined // Event status (confirmed, tentative, cancelled), htmlLink: string | undefined // Link to the event in Calendar UI, created: string | undefined // Event creation timestamp, updated: string | undefined // Event last updated timestamp, summary: string | undefined // Event title, description: string | undefined // Event description, location: string | undefined // Event location, start: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event start date/time, end: { dateTime: string | undefined // RFC3339 timestamp, e.g. 2025-09-10T10:00:00-07:00, date: string | undefined // All-day date in YYYY-MM-DD (mutually exclusive with dateTime), timeZone: string | undefined // Time zone for the event time } | undefined // Event end date/time, attendees: { email: string // Attendee email, optional: boolean | undefined // Whether this attendee is optional, responseStatus: \"needsAction\" | \"declined\" | \"tentative\" | \"accepted\" | undefined // Response status of the attendee, displayName: string | undefined // Display name of the attendee }[] | undefined // List of event attendees, organizer: { email: string | undefined // Organizer email address, displayName: string | undefined // Organizer display name } | undefined // Event organizer information, hangoutLink: string | undefined // Google Hangout/Meet link for the event, conferenceData: unknown | undefined // Conference data for virtual meetings } | 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 flowId: number | undefined,\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 bubblesUsed: string[] // List of bubble names used in the generated flow,\n tokenUsage: { inputTokens: number, outputTokens: number, totalTokens: number, modelName: string | undefined } | undefined,\n bubbleCount: number | undefined,\n codeLength: number | undefined\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// flowId: number | undefined,\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// bubblesUsed: string[] // List of bubble names used in the generated flow,\n// tokenUsage: { inputTokens: number, outputTokens: number, totalTokens: number, modelName: string | undefined } | undefined,\n// bubbleCount: number | undefined,\n// codeLength: number | undefined\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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"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 // Total execution time in milliseconds, rowCount: number | undefined // Number of rows returned, wordCount: number | undefined // Word count of response } | 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Total execution time in milliseconds, rowCount: number | undefined // Number of rows returned, wordCount: number | undefined // Word count of response } | 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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" // AI model to use (format: provider/model-name), temperature: number // Temperature for response randomness (0 = deterministic, 2 = very random), maxTokens: number | undefined // Maximum number of tokens to generate in response } // AI model configuration including provider, temperature, and tokens,\n tools: { name: string // Name of the tool bubble to enable for the AI agent, credentials: Record<string, string> | undefined // Credential types to use for the tool bubble (injected at runtime), config: Record<string, unknown> | undefined // Configuration for the tool bubble }[] // 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 // Applied verbosity level, technicalityLevel: string // Applied technicality level, wordCount: number // Total word count of response, blockCount: number | undefined // Number of Slack blocks generated } // Metadata about the formatting,\n toolCalls: { tool: string // Name of the tool that was called, input: unknown // Input parameters passed to the tool, output: unknown // Output returned by the tool }[] | 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Applied verbosity level, technicalityLevel: string // Applied technicality level, wordCount: number // Total word count of response, blockCount: number | undefined // Number of Slack blocks generated } // Metadata about the formatting,\n// toolCalls: { tool: string // Name of the tool that was called, input: unknown // Input parameters passed to the tool, output: unknown // Output returned by the tool }[] | 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 // Base64 encoded image data, 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 // Markdown content for this page, 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Field ID from discovery or auto-generated, fieldName: string // Descriptive name generated based on PDF content, confidence: number // AI confidence in the field identification (0.0-1.0) }[] // 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Field ID from discovery or auto-generated, originalFieldName: string | undefined // Original field name from discovery for precise matching, fieldName: string // Descriptive name generated based on PDF content, value: string // Value to fill in the field based on client information, confidence: number // AI confidence in the field identification and value assignment (0.0-1.0) }[] // 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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" // AI model to use for document analysis, temperature: number // Temperature for AI responses (lower = more consistent), maxTokens: number // Maximum tokens for AI response, jsonMode: boolean // Enable JSON mode to ensure clean JSON output } // 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 // Column name, type: \"string\" | \"number\" | \"integer\" | \"float\" | \"date\" | \"boolean\" // Data type of the column, description: string // Description of what this column contains }[] // Column definitions for the structured data,\n rows: Record<string, unknown>[] // Array of data rows extracted from documents,\n metadata: { totalDocuments: number // Number of documents processed, totalRows: number // Number of data rows extracted, totalColumns: number // Number of columns in the result, processingTime: number // Processing time in milliseconds, extractedFrom: string[] // Summary of document sources } // Metadata about the extraction process,\n generatedFiles: { html: string | undefined // Generated HTML table, csv: string | undefined // Generated CSV data, json: string | undefined // Generated JSON data } // Generated files in requested formats,\n aiAnalysis: { model: string // AI model used, iterations: number // Number of AI iterations, processingTime: number | undefined // AI processing time } // 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Column name, type: \"string\" | \"number\" | \"integer\" | \"float\" | \"date\" | \"boolean\" // Data type of the column, description: string // Description of what this column contains }[] // Column definitions for the structured data,\n// rows: Record<string, unknown>[] // Array of data rows extracted from documents,\n// metadata: { totalDocuments: number // Number of documents processed, totalRows: number // Number of data rows extracted, totalColumns: number // Number of columns in the result, processingTime: number // Processing time in milliseconds, extractedFrom: string[] // Summary of document sources } // Metadata about the extraction process,\n// generatedFiles: { html: string | undefined // Generated HTML table, csv: string | undefined // Generated CSV data, json: string | undefined // Generated JSON data } // Generated files in requested formats,\n// aiAnalysis: { model: string // AI model used, iterations: number // Number of AI iterations, processingTime: number | undefined // AI processing time } // 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 // Maintain original document structure and hierarchy, includeVisualDescriptions: boolean // Include detailed descriptions of charts, images, and diagrams, extractNumericalData: boolean // Extract specific numerical values from charts and tables, combinePages: boolean // Deprecated: Pages are always kept separate with clear headers } // Options for document conversion and parsing,\n imageOptions: { format: \"png\" | \"jpeg\" // Output image format for PDF conversion, quality: number // Image quality (0.1-1.0, higher = better quality), dpi: number // Output DPI for PDF conversion (higher = better quality), pages: number[] | undefined // Specific page numbers to process (1-indexed) } // Options for PDF to images conversion,\n aiOptions: { model: \"openai/gpt-5\" | \"openai/gpt-5-mini\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"openrouter/x-ai/grok-code-fast-1\" | \"openrouter/z-ai/glm-4.6\" // AI model to use for document analysis and conversion, temperature: number // Temperature for AI responses (balanced for accuracy vs recitation), maxTokens: number // Maximum tokens for AI response, jsonMode: boolean // Use JSON mode for structured output } // AI agent configuration options,\n storageOptions: { uploadImages: boolean // Whether to upload converted page images to S3, bucketName: string | undefined // S3 bucket name for image uploads, pageImageUrls: { pageNumber: number, uploadUrl: string, fileName: string }[] | undefined // Pre-generated upload URLs for page images, userId: string | undefined // User ID for secure file isolation } | 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 // Page number (1-indexed), markdown: string // Markdown content for this page, hasCharts: boolean // Whether this page contains charts or graphs, hasTables: boolean // Whether this page contains tables, hasImages: boolean // Whether this page contains images }[] // Per-page analysis results,\n metadata: { totalPages: number // Total number of pages processed, processedPages: number // Number of pages successfully processed, hasVisualElements: boolean // Whether document contains charts, tables, or images, processingTime: number // Total processing time in milliseconds, imageFormat: string // Image format used for conversion, imageDpi: number // DPI used for image conversion } // Metadata about the parsing process,\n conversionSummary: { totalCharacters: number // Total characters in generated markdown, tablesExtracted: number // Number of tables converted to markdown, chartsDescribed: number // Number of charts and graphs described, imagesDescribed: number // Number of images described } // Summary of conversion results,\n aiAnalysis: { model: string // AI model used for analysis, iterations: number // Number of AI iterations, processingTime: number // AI processing time in milliseconds } // 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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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 // Page number (1-indexed), markdown: string // Markdown content for this page, hasCharts: boolean // Whether this page contains charts or graphs, hasTables: boolean // Whether this page contains tables, hasImages: boolean // Whether this page contains images }[] // Per-page analysis results,\n// metadata: { totalPages: number // Total number of pages processed, processedPages: number // Number of pages successfully processed, hasVisualElements: boolean // Whether document contains charts, tables, or images, processingTime: number // Total processing time in milliseconds, imageFormat: string // Image format used for conversion, imageDpi: number // DPI used for image conversion } // Metadata about the parsing process,\n// conversionSummary: { totalCharacters: number // Total characters in generated markdown, tablesExtracted: number // Number of tables converted to markdown, chartsDescribed: number // Number of charts and graphs described, imagesDescribed: number // Number of images described } // Summary of conversion results,\n// aiAnalysis: { model: string // AI model used for analysis, iterations: number // Number of AI iterations, processingTime: number // AI processing time in milliseconds } // 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 // Name of the bubble, alias: string | undefined // Short alias for the bubble, shortDescription: string // Brief description of the bubble functionality, useCase: string // Primary use cases for the bubble, type: string // Type of bubble (service, workflow, tool) }[] // 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 // Name of the bubble, alias: string | undefined // Short alias for the bubble, shortDescription: string // Brief description of the bubble functionality, useCase: string // Primary use cases for the bubble, type: string // Type of bubble (service, workflow, tool) }[] // 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 // Name of the column, dataTypeID: number | undefined // PostgreSQL data type ID for the column }[] | 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 // Name of the column, dataTypeID: number | undefined // PostgreSQL data type ID for the column }[] | 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
+ "DATABASE_CRED"
334
+ ]
335
+ },
336
+ {
337
+ "name": "chart-js-tool",
338
+ "alias": "chart",
339
+ "type": "tool",
340
+ "shortDescription": "Generate Chart.js configurations from data for interactive visualizations",
341
+ "useCase": "- Converting SQL query results into visual charts",
342
+ "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 // Chart title, xAxisLabel: string | undefined // X-axis label, yAxisLabel: string | undefined // Y-axis label, colorScheme: \"default\" | \"viridis\" | \"plasma\" | \"inferno\" | \"magma\" | \"blues\" | \"greens\" | \"reds\" | \"oranges\" | \"categorical\" // Color scheme for the chart, responsive: boolean // Make chart responsive, maintainAspectRatio: boolean // Maintain aspect ratio, showLegend: boolean // Show chart legend, showTooltips: boolean // Show tooltips on hover } | 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}",
343
+ "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}",
344
+ "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);",
345
+ "requiredCredentials": []
346
+ },
347
+ {
348
+ "name": "bubbleflow-validation-tool",
349
+ "alias": "validate-bubbleflow",
350
+ "type": "tool",
351
+ "shortDescription": "Validates BubbleFlow TypeScript code for syntax and structure",
352
+ "useCase": "- When an AI agent needs to validate user-provided BubbleFlow code",
353
+ "inputSchema": "{\n code: string // TypeScript code to validate,\n options: { includeDetails: boolean // Include detailed bubble analysis, strictMode: boolean // Enable strict TypeScript validation } | 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}",
354
+ "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 // Variable name assigned to the bubble, bubbleName: string // Type of bubble (e.g., postgresql, slack), className: string // Bubble class name (e.g., PostgreSQLBubble), hasAwait: boolean // Whether the bubble call is awaited, hasActionCall: boolean // Whether .action() is called, parameterCount: number // Number of parameters passed to the bubble }[] | undefined // Details about each bubble found,\n metadata: { validatedAt: string // Timestamp when validation was performed, codeLength: number // Length of the code in characters, strictMode: boolean // Whether strict mode was used },\n success: boolean // Whether the validation operation was successful,\n error: string // Error message if validation failed\n}",
355
+ "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 // Variable name assigned to the bubble, bubbleName: string // Type of bubble (e.g., postgresql, slack), className: string // Bubble class name (e.g., PostgreSQLBubble), hasAwait: boolean // Whether the bubble call is awaited, hasActionCall: boolean // Whether .action() is called, parameterCount: number // Number of parameters passed to the bubble }[] | undefined // Details about each bubble found,\n// metadata: { validatedAt: string // Timestamp when validation was performed, codeLength: number // Length of the code in characters, strictMode: boolean // Whether strict mode was used },\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);",
356
+ "requiredCredentials": []
357
+ },
358
+ {
359
+ "name": "web-search-tool",
360
+ "alias": "websearch",
361
+ "type": "tool",
362
+ "shortDescription": "Performs web searches using Firecrawl to find current information from the web",
363
+ "useCase": "- Finding current events and news",
364
+ "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}",
365
+ "outputSchema": "{\n results: { title: string // Title of the search result, url: string // URL of the search result, content: string // Content snippet from the search result }[] // 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}",
366
+ "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 // Title of the search result, url: string // URL of the search result, content: string // Content snippet from the search result }[] // 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);",
367
+ "requiredCredentials": [
368
+ "FIRECRAWL_API_KEY"
369
+ ]
370
+ },
371
+ {
372
+ "name": "web-scrape-tool",
373
+ "alias": "scrape",
374
+ "type": "tool",
375
+ "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",
376
+ "useCase": "General purpose bubble for various workflow needs",
377
+ "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\" // Action type to perform, milliseconds: number | undefined // Time to wait in milliseconds (for wait), selector: string | undefined // CSS selector to interact with (wait/click/write/scroll), text: string | undefined // Text to write (for write), key: string | undefined // Key to press (e.g., \"Enter\") (for press), direction: \"up\" | \"down\" | undefined // Scroll direction (for scroll), script: string | undefined // JavaScript code (for executeJavascript) }[] | 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}",
378
+ "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}",
379
+ "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);",
380
+ "requiredCredentials": [
381
+ "FIRECRAWL_API_KEY"
382
+ ]
383
+ },
384
+ {
385
+ "name": "web-extract-tool",
386
+ "alias": "extract",
387
+ "type": "tool",
388
+ "shortDescription": "Extracts structured data from web pages using Firecrawl AI-powered extraction with custom prompts and schemas",
389
+ "useCase": "General purpose bubble for various workflow needs",
390
+ "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}",
391
+ "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}",
392
+ "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);",
393
+ "requiredCredentials": [
394
+ "FIRECRAWL_API_KEY"
395
+ ]
396
+ },
397
+ {
398
+ "name": "research-agent-tool",
399
+ "alias": "research",
400
+ "type": "tool",
401
+ "shortDescription": "AI-powered research agent that searches and scrapes the internet to gather structured information",
402
+ "useCase": "- Market research with structured competitor analysis",
403
+ "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\" | \"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\" | \"anthropic/claude-haiku-4-5\" | \"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-pro),\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}",
404
+ "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}",
405
+ "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\", \"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\", \"anthropic/claude-haiku-4-5\", \"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-pro),\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);",
406
+ "requiredCredentials": [
407
+ "FIRECRAWL_API_KEY",
408
+ "GOOGLE_GEMINI_CRED"
409
+ ]
410
+ },
411
+ {
412
+ "name": "reddit-scrape-tool",
413
+ "alias": "reddit",
414
+ "type": "tool",
415
+ "shortDescription": "Scrapes posts from any Reddit subreddit with flexible filtering and sorting options",
416
+ "useCase": "General purpose bubble for various workflow needs",
417
+ "inputSchema": "{\n subreddit: unknown // Name of the subreddit to scrape (with or without r/ prefix),\n limit: number // Maximum number of posts to fetch (1-1000, 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}",
418
+ "outputSchema": "{\n posts: { title: string // Post title, url: string // Post URL (external link or Reddit permalink), author: string // Username of the post author, score: number // Post upvote score, numComments: number // Number of comments on the post, createdUtc: number // Post creation timestamp (Unix UTC), postUrl: string // Reddit url to the post, selftext: string // Post content text (for text posts/self posts). Empty for link posts which don't have text content., subreddit: string // Subreddit name, postHint: string | null | undefined // Post type hint (image, video, link, etc.), isSelf: boolean // Whether this is a text post (true) or link post (false), thumbnail: string | undefined // Thumbnail image URL if available, domain: string | undefined // Domain of external link, flair: string | undefined // Post flair text }[] // Array of scraped Reddit posts,\n metadata: { subreddit: string // Subreddit that was scraped, requestedLimit: number // Number of posts requested, actualCount: number // Actual number of posts returned, filteredCount: number // Number of posts after filtering, sort: string // Sorting method used, timeFilter: string | undefined // Time filter used (if any), scrapedAt: string // ISO timestamp when scraping occurred, apiEndpoint: string // Reddit API endpoint used } // Metadata about the scraping operation,\n success: boolean // Whether the scraping was successful,\n error: string // Error message if scraping failed\n}",
419
+ "usageExample": "// Example usage of reddit-scrape-tool bubble\nconst redditScrapeTool = new RedditScrapeToolBubble({\n limit: 100 // default, // Maximum number of posts to fetch (1-1000, 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 // Post title, url: string // Post URL (external link or Reddit permalink), author: string // Username of the post author, score: number // Post upvote score, numComments: number // Number of comments on the post, createdUtc: number // Post creation timestamp (Unix UTC), postUrl: string // Reddit url to the post, selftext: string // Post content text (for text posts/self posts). Empty for link posts which don't have text content., subreddit: string // Subreddit name, postHint: string | null | undefined // Post type hint (image, video, link, etc.), isSelf: boolean // Whether this is a text post (true) or link post (false), thumbnail: string | undefined // Thumbnail image URL if available, domain: string | undefined // Domain of external link, flair: string | undefined // Post flair text }[] // Array of scraped Reddit posts,\n// metadata: { subreddit: string // Subreddit that was scraped, requestedLimit: number // Number of posts requested, actualCount: number // Actual number of posts returned, filteredCount: number // Number of posts after filtering, sort: string // Sorting method used, timeFilter: string | undefined // Time filter used (if any), scrapedAt: string // ISO timestamp when scraping occurred, apiEndpoint: string // Reddit API endpoint used } // 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);",
420
+ "requiredCredentials": []
421
+ },
422
+ {
423
+ "name": "instagram-tool",
424
+ "alias": "ig",
425
+ "type": "tool",
426
+ "shortDescription": "Scrape Instagram profiles and posts with a simple, unified interface. Works with individual user profiles and hashtags.",
427
+ "useCase": "**",
428
+ "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}",
429
+ "outputSchema": "{\n operation: \"scrapeProfile\" | \"scrapeHashtag\" // Operation that was performed,\n posts: { url: string | null // Post URL, caption: string | null // Post caption text, likesCount: number | null // Number of likes, commentsCount: number | null // Number of comments, ownerUsername: string | null // Post owner username, timestamp: string | null // Post timestamp (ISO format), type: \"image\" | \"video\" | \"carousel\" | null // Post media type, displayUrl: string | null // Main display image URL, hashtags: string[] | null // Hashtags in the post }[] // Array of Instagram posts scraped,\n profiles: { username: string // Instagram username, fullName: string | null // Full name, bio: string | null // Profile bio, followersCount: number | null // Number of followers, followingCount: number | null // Number of following, postsCount: number | null // Total posts, isVerified: boolean | null // Verification status, profilePicUrl: string | null // Profile picture URL }[] | 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}",
430
+ "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 // Post URL, caption: string | null // Post caption text, likesCount: number | null // Number of likes, commentsCount: number | null // Number of comments, ownerUsername: string | null // Post owner username, timestamp: string | null // Post timestamp (ISO format), type: \"image\" | \"video\" | \"carousel\" | null // Post media type, displayUrl: string | null // Main display image URL, hashtags: string[] | null // Hashtags in the post }[] // Array of Instagram posts scraped,\n// profiles: { username: string // Instagram username, fullName: string | null // Full name, bio: string | null // Profile bio, followersCount: number | null // Number of followers, followingCount: number | null // Number of following, postsCount: number | null // Total posts, isVerified: boolean | null // Verification status, profilePicUrl: string | null // Profile picture URL }[] | 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);",
431
+ "requiredCredentials": [
432
+ "APIFY_CRED"
433
+ ]
434
+ },
435
+ {
436
+ "name": "linkedin-tool",
437
+ "alias": "li",
438
+ "type": "tool",
439
+ "shortDescription": "Scrape LinkedIn posts by profile or search by keyword. Get engagement metrics, media, and complete metadata.",
440
+ "useCase": "**",
441
+ "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}",
442
+ "outputSchema": "{\n operation: \"scrapePosts\" | \"searchPosts\" // Operation that was performed,\n posts: { urn: string | null // Post URN, fullUrn: string | null // Full URN with prefix, postedAt: { date: string | null // Post date (formatted string), relative: string | null // Relative time (e.g., \"2 days ago\"), timestamp: number | null // Unix timestamp in milliseconds } | null // When post was created, text: string | null // Post text content, url: string | null // Post URL, postType: string | null // Post type (regular, quote, etc), author: { firstName: string | null // Author first name, lastName: string | null // Author last name, headline: string | null // Author headline/title, username: string | null // Author username, profileUrl: string | null // Author profile URL, profilePicture: string | null // Author profile picture URL } | null // Post author information, stats: { totalReactions: number | null // Total number of reactions, like: number | null // Number of likes, support: number | null // Number of support reactions, love: number | null // Number of love reactions, insight: number | null // Number of insight reactions, celebrate: number | null // Number of celebrate reactions, funny: number | null // Number of funny reactions, comments: number | null // Number of comments, reposts: number | null // Number of reposts } | null // Post engagement statistics, media: { type: string | null // Media type (image, video, images), url: string | null // Media URL, thumbnail: string | null // Media thumbnail URL, images: { url: string | null, width: number | null, height: number | null }[] | null // Array of images for multi-image posts } | null // Post media content, article: { url: string | null, title: string | null, subtitle: string | null, thumbnail: string | null } | null // Shared article information, document: { title: string | null, pageCount: number | null, url: string | null, thumbnail: string | null } | null // Shared document information, resharedPost: { urn: string | null, postedAt: { date: string | null // Post date (formatted string), relative: string | null // Relative time (e.g., \"2 days ago\"), timestamp: number | null // Unix timestamp in milliseconds } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null // Author first name, lastName: string | null // Author last name, headline: string | null // Author headline/title, username: string | null // Author username, profileUrl: string | null // Author profile URL, profilePicture: string | null // Author profile picture URL } | null, stats: { totalReactions: number | null // Total number of reactions, like: number | null // Number of likes, support: number | null // Number of support reactions, love: number | null // Number of love reactions, insight: number | null // Number of insight reactions, celebrate: number | null // Number of celebrate reactions, funny: number | null // Number of funny reactions, comments: number | null // Number of comments, reposts: number | null // Number of reposts } | null, media: { type: string | null // Media type (image, video, images), url: string | null // Media URL, thumbnail: string | null // Media thumbnail URL, images: { url: string | null, width: number | null, height: number | null }[] | null // Array of images for multi-image posts } | null } | null // Original post that was reshared }[] // 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}",
443
+ "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 // Post URN, fullUrn: string | null // Full URN with prefix, postedAt: { date: string | null // Post date (formatted string), relative: string | null // Relative time (e.g., \"2 days ago\"), timestamp: number | null // Unix timestamp in milliseconds } | null // When post was created, text: string | null // Post text content, url: string | null // Post URL, postType: string | null // Post type (regular, quote, etc), author: { firstName: string | null // Author first name, lastName: string | null // Author last name, headline: string | null // Author headline/title, username: string | null // Author username, profileUrl: string | null // Author profile URL, profilePicture: string | null // Author profile picture URL } | null // Post author information, stats: { totalReactions: number | null // Total number of reactions, like: number | null // Number of likes, support: number | null // Number of support reactions, love: number | null // Number of love reactions, insight: number | null // Number of insight reactions, celebrate: number | null // Number of celebrate reactions, funny: number | null // Number of funny reactions, comments: number | null // Number of comments, reposts: number | null // Number of reposts } | null // Post engagement statistics, media: { type: string | null // Media type (image, video, images), url: string | null // Media URL, thumbnail: string | null // Media thumbnail URL, images: { url: string | null, width: number | null, height: number | null }[] | null // Array of images for multi-image posts } | null // Post media content, article: { url: string | null, title: string | null, subtitle: string | null, thumbnail: string | null } | null // Shared article information, document: { title: string | null, pageCount: number | null, url: string | null, thumbnail: string | null } | null // Shared document information, resharedPost: { urn: string | null, postedAt: { date: string | null // Post date (formatted string), relative: string | null // Relative time (e.g., \"2 days ago\"), timestamp: number | null // Unix timestamp in milliseconds } | null, text: string | null, url: string | null, postType: string | null, author: { firstName: string | null // Author first name, lastName: string | null // Author last name, headline: string | null // Author headline/title, username: string | null // Author username, profileUrl: string | null // Author profile URL, profilePicture: string | null // Author profile picture URL } | null, stats: { totalReactions: number | null // Total number of reactions, like: number | null // Number of likes, support: number | null // Number of support reactions, love: number | null // Number of love reactions, insight: number | null // Number of insight reactions, celebrate: number | null // Number of celebrate reactions, funny: number | null // Number of funny reactions, comments: number | null // Number of comments, reposts: number | null // Number of reposts } | null, media: { type: string | null // Media type (image, video, images), url: string | null // Media URL, thumbnail: string | null // Media thumbnail URL, images: { url: string | null, width: number | null, height: number | null }[] | null // Array of images for multi-image posts } | null } | null // Original post that was reshared }[] // 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);",
444
+ "requiredCredentials": [
445
+ "APIFY_CRED"
446
+ ]
447
+ },
448
+ {
449
+ "name": "youtube-tool",
450
+ "alias": "yt",
451
+ "type": "tool",
452
+ "shortDescription": "Search YouTube videos, extract transcripts, and scrape channel content with a simple interface",
453
+ "useCase": "General purpose bubble for various workflow needs",
454
+ "inputSchema": "{\n operation: \"searchVideos\" | \"getTranscript\" | \"scrapeChannel\" // Operation: searchVideos for search/URLs, getTranscript for transcripts, scrapeChannel for channel videos. Not all videos will have transcript available.,\n searchQueries: string[] | undefined // Search queries for YouTube (for searchVideos). Examples: [\"AI tutorials\", \"react hooks\"],\n videoUrls: string[] | undefined // Direct YouTube URLs - videos, channels, playlists (for searchVideos or getTranscript),\n channelUrl: string | undefined // YouTube channel URL (for scrapeChannel operation),\n videoUrl: string | undefined // Single video URL for transcript extraction (for getTranscript),\n maxResults: number | undefined // Max videos to fetch (default: 20),\n includeShorts: boolean | undefined // Include YouTube Shorts in results,\n credentials: Record<string, string> | undefined // Required credentials (auto-injected)\n}",
455
+ "outputSchema": "{\n operation: \"searchVideos\" | \"getTranscript\" | \"scrapeChannel\" // Operation performed,\n videos: { title: string | null // Video title, id: string | null // YouTube video ID, url: string | null // Video URL, viewCount: number | null // Number of views, likes: number | null // Number of likes, date: string | null // Upload date (ISO format), channelName: string | null // Channel name, channelUrl: string | null // Channel URL, subscribers: number | null // Number of channel subscribers, duration: string | null // Video duration (HH:MM:SS), description: string | null // Video description, comments: number | null // Number of comments, thumbnail: string | null // Thumbnail URL }[] | undefined // Array of YouTube videos,\n transcript: { start: string | null // Start time in seconds, duration: string | null // Duration in seconds, text: string | null // Transcript text }[] | undefined // Video transcript with timestamps,\n fullTranscriptText: string | undefined // Complete transcript as plain text,\n totalResults: number // Total number of results,\n success: boolean // Whether operation succeeded,\n error: string // Error message if failed\n}",
456
+ "usageExample": "// Example usage of youtube-tool bubble\nconst youtubeTool = new YoutubeToolBubble({\n operation: \"searchVideos\" // options: \"searchVideos\", \"getTranscript\", \"scrapeChannel\", // Operation: searchVideos for search/URLs, getTranscript for transcripts, scrapeChannel for channel videos. Not all videos will have transcript available.,\n searchQueries: [\"example string\"], // Search queries for YouTube (for searchVideos). Examples: [\"AI tutorials\", \"react hooks\"],\n videoUrls: [\"example string\"], // Direct YouTube URLs - videos, channels, playlists (for searchVideos or getTranscript),\n channelUrl: \"example string\", // YouTube channel URL (for scrapeChannel operation),\n videoUrl: \"example string\", // Single video URL for transcript extraction (for getTranscript),\n maxResults: 20 // default, // Max videos to fetch (default: 20),\n includeShorts: false // default, // Include YouTube Shorts in results,\n});\n\nconst result = await youtubeTool.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: \"searchVideos\" | \"getTranscript\" | \"scrapeChannel\" // Operation performed,\n// videos: { title: string | null // Video title, id: string | null // YouTube video ID, url: string | null // Video URL, viewCount: number | null // Number of views, likes: number | null // Number of likes, date: string | null // Upload date (ISO format), channelName: string | null // Channel name, channelUrl: string | null // Channel URL, subscribers: number | null // Number of channel subscribers, duration: string | null // Video duration (HH:MM:SS), description: string | null // Video description, comments: number | null // Number of comments, thumbnail: string | null // Thumbnail URL }[] | undefined // Array of YouTube videos,\n// transcript: { start: string | null // Start time in seconds, duration: string | null // Duration in seconds, text: string | null // Transcript text }[] | undefined // Video transcript with timestamps,\n// fullTranscriptText: string | undefined // Complete transcript as plain text,\n// totalResults: number // Total number of results,\n// success: boolean // Whether operation succeeded,\n// error: string // Error message if failed\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
457
+ "requiredCredentials": [
458
+ "APIFY_CRED"
459
+ ]
460
+ },
461
+ {
462
+ "name": "web-crawl-tool",
463
+ "alias": "crawl",
464
+ "type": "tool",
465
+ "shortDescription": "Multi-page web crawling tool for exploring entire websites and subdomains.",
466
+ "useCase": "General purpose bubble for various workflow needs",
467
+ "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}",
468
+ "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}",
469
+ "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);",
470
+ "requiredCredentials": [
471
+ "FIRECRAWL_API_KEY"
472
+ ]
473
+ },
474
+ {
475
+ "name": "bubbleflow-generator",
476
+ "alias": "generate-flow",
477
+ "type": "workflow",
478
+ "shortDescription": "Generate BubbleFlow code from natural language",
479
+ "useCase": "General purpose bubble for various workflow needs",
480
+ "inputSchema": "{\n prompt: string // Natural language description of the desired BubbleFlow,\n credentials: Record<string, string> | undefined // Credentials for AI agent operations\n}",
481
+ "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 flowId: number | undefined,\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 bubblesUsed: string[] // List of bubble names used in the generated flow,\n tokenUsage: { inputTokens: number, outputTokens: number, totalTokens: number, modelName: string | undefined } | undefined,\n bubbleCount: number | undefined,\n codeLength: number | undefined\n}",
482
+ "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// flowId: number | undefined,\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// bubblesUsed: string[] // List of bubble names used in the generated flow,\n// tokenUsage: { inputTokens: number, outputTokens: number, totalTokens: number, modelName: string | undefined } | undefined,\n// bubbleCount: number | undefined,\n// codeLength: number | undefined\n// }\n\n// Access the actual data\nconst actualData = result.data;\nconsole.log(actualData);",
483
+ "requiredCredentials": [
484
+ "GOOGLE_GEMINI_CRED",
485
+ "OPENROUTER_CRED"
486
+ ]
487
+ }
488
+ ]
489
+ }