From 4da5dd7f74461b0df853a78676c49b41918671f9 Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 14:58:31 -0800 Subject: [PATCH 01/34] fix(nextjs): upgrade nextjs to patch security vuln (#2320) --- apps/docs/package.json | 2 +- apps/sim/package.json | 6 +++--- bun.lock | 30 +++++++++++++++--------------- package.json | 6 +++--- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 14bcd4922b..8987f561f8 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -19,7 +19,7 @@ "fumadocs-mdx": "14.1.0", "fumadocs-ui": "16.2.3", "lucide-react": "^0.511.0", - "next": "16.0.7", + "next": "16.0.9", "next-themes": "^0.4.6", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/apps/sim/package.json b/apps/sim/package.json index fe68af4ca9..475b75943a 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -99,7 +99,7 @@ "mammoth": "^1.9.0", "mysql2": "3.14.3", "nanoid": "^3.3.7", - "next": "16.0.7", + "next": "16.0.9", "next-mdx-remote": "^5.0.0", "next-runtime-env": "3.3.0", "next-themes": "^0.4.6", @@ -168,8 +168,8 @@ "sharp" ], "overrides": { - "next": "16.0.7", - "@next/env": "16.0.7", + "next": "16.0.9", + "@next/env": "16.0.9", "drizzle-orm": "^0.44.5", "postgres": "^3.4.5" } diff --git a/bun.lock b/bun.lock index ec5f0c82c7..687be5911f 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ }, "devDependencies": { "@biomejs/biome": "2.0.0-beta.5", - "@next/env": "16.0.7", + "@next/env": "16.0.9", "@octokit/rest": "^21.0.0", "@tailwindcss/typography": "0.5.19", "@types/nodemailer": "7.0.4", @@ -49,7 +49,7 @@ "fumadocs-mdx": "14.1.0", "fumadocs-ui": "16.2.3", "lucide-react": "^0.511.0", - "next": "16.0.7", + "next": "16.0.9", "next-themes": "^0.4.6", "react": "19.2.1", "react-dom": "19.2.1", @@ -147,7 +147,7 @@ "mammoth": "^1.9.0", "mysql2": "3.14.3", "nanoid": "^3.3.7", - "next": "16.0.7", + "next": "16.0.9", "next-mdx-remote": "^5.0.0", "next-runtime-env": "3.3.0", "next-themes": "^0.4.6", @@ -260,9 +260,9 @@ "sharp", ], "overrides": { - "@next/env": "16.0.7", + "@next/env": "16.0.9", "drizzle-orm": "^0.44.5", - "next": "16.0.7", + "next": "16.0.9", "postgres": "^3.4.5", "react": "19.2.1", "react-dom": "19.2.1", @@ -744,23 +744,23 @@ "@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.84", "", { "os": "win32", "cpu": "x64" }, "sha512-YSs8ncurc1xzegUMNnQUTYrdrAuaXdPMOa+iYYyAxydOtg0ppV386hyYMsy00Yip1NlTgLCseRG4sHSnjQx6og=="], - "@next/env": ["@next/env@16.0.7", "", {}, "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw=="], + "@next/env": ["@next/env@16.0.9", "", {}, "sha512-6284pl8c8n9PQidN63qjPVEu1uXXKjnmbmaLebOzIfTrSXdGiAPsIMRi4pk/+v/ezqweE1/B8bFqiAAfC6lMXg=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-j06fWg/gPqiWjK+sEpCDsh5gX+Bdy9gnPYjFqMBvBEOIcCFy1/ecF6pY6XAce7WyCJAbBPVb+6GvpmUZKNq0oQ=="], - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-FRYYz5GSKUkfvDSjd5hgHME2LgYjfOLBmhRVltbs3oRNQQf9n5UTQMmIu/u5vpkjJFV4L2tqo8duGqDxdQOFwg=="], - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-EI2klFVL8tOyEIX5J1gXXpm1YuChmDy4R+tHoNjkCHUmBJqXioYErX/O2go4pEhjxkAxHp2i8y5aJcRz2m5NqQ=="], - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-vq/5HeGvowhDPMrpp/KP4GjPVhIXnwNeDPF5D6XK6ta96UIt+C0HwJwuHYlwmn0SWyNANqx1Mp6qSVDXwbFKsw=="], - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.9", "", { "os": "linux", "cpu": "x64" }, "sha512-GlUdJwy2leA/HnyRYxJ1ZJLCJH+BxZfqV4E0iYLrJipDKxWejWpPtZUdccPmCfIEY9gNBO7bPfbG6IIgkt0qXg=="], - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.9", "", { "os": "linux", "cpu": "x64" }, "sha512-UCtOVx4N8AHF434VPwg4L0KkFLAd7pgJShzlX/hhv9+FDrT7/xCuVdlBsCXH7l9yCA/wHl3OqhMbIkgUluriWA=="], - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-tQjtDGtv63mV3n/cZ4TH8BgUvKTSFlrF06yT5DyRmgQuj5WEjBUDy0W3myIW5kTRYMPrLn42H3VfCNwBH6YYiA=="], - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.7", "", { "os": "win32", "cpu": "x64" }, "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.9", "", { "os": "win32", "cpu": "x64" }, "sha512-y9AGACHTBwnWFLq5B5Fiv3FEbXBusdPb60pgoerB04CV/pwjY1xQNdoTNxAv7eUhU2k1CKnkN4XWVuiK07uOqA=="], "@noble/ciphers": ["@noble/ciphers@2.1.1", "", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="], @@ -2634,7 +2634,7 @@ "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="], - "next": ["next@16.0.7", "", { "dependencies": { "@next/env": "16.0.7", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.7", "@next/swc-darwin-x64": "16.0.7", "@next/swc-linux-arm64-gnu": "16.0.7", "@next/swc-linux-arm64-musl": "16.0.7", "@next/swc-linux-x64-gnu": "16.0.7", "@next/swc-linux-x64-musl": "16.0.7", "@next/swc-win32-arm64-msvc": "16.0.7", "@next/swc-win32-x64-msvc": "16.0.7", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A=="], + "next": ["next@16.0.9", "", { "dependencies": { "@next/env": "16.0.9", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.9", "@next/swc-darwin-x64": "16.0.9", "@next/swc-linux-arm64-gnu": "16.0.9", "@next/swc-linux-arm64-musl": "16.0.9", "@next/swc-linux-x64-gnu": "16.0.9", "@next/swc-linux-x64-musl": "16.0.9", "@next/swc-win32-arm64-msvc": "16.0.9", "@next/swc-win32-x64-msvc": "16.0.9", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-Xk5x/wEk6ADIAtQECLo1uyE5OagbQCiZ+gW4XEv24FjQ3O2PdSkvgsn22aaseSXC7xg84oONvQjFbSTX5YsMhQ=="], "next-mdx-remote": ["next-mdx-remote@5.0.0", "", { "dependencies": { "@babel/code-frame": "^7.23.5", "@mdx-js/mdx": "^3.0.1", "@mdx-js/react": "^3.0.1", "unist-util-remove": "^3.1.0", "vfile": "^6.0.1", "vfile-matter": "^5.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-RNNbqRpK9/dcIFZs/esQhuLA8jANqlH694yqoDBK8hkVdJUndzzGmnPHa2nyi90N4Z9VmzuSWNRpr5ItT3M7xQ=="], diff --git a/package.json b/package.json index 26c5017001..21bcdd228a 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "overrides": { "react": "19.2.1", "react-dom": "19.2.1", - "next": "16.0.7", - "@next/env": "16.0.7", + "next": "16.0.9", + "@next/env": "16.0.9", "drizzle-orm": "^0.44.5", "postgres": "^3.4.5" }, @@ -56,7 +56,7 @@ }, "devDependencies": { "@biomejs/biome": "2.0.0-beta.5", - "@next/env": "16.0.7", + "@next/env": "16.0.9", "@octokit/rest": "^21.0.0", "@tailwindcss/typography": "0.5.19", "@types/nodemailer": "7.0.4", From 8d4f2e02336dce7dd67477b612f5c43749538296 Mon Sep 17 00:00:00 2001 From: Esteban Canela Date: Thu, 11 Dec 2025 20:14:39 -0300 Subject: [PATCH 02/34] feat(tools): added sqs integration (#2310) * feat(tools): added sqs integration * remove console log * fix linter issues --- apps/docs/components/icons.tsx | 29 ++++ apps/docs/components/ui/icon-mapping.ts | 2 + apps/docs/content/docs/en/tools/meta.json | 1 + apps/docs/content/docs/en/tools/sqs.mdx | 63 +++++++++ apps/sim/app/api/tools/sqs/send/route.ts | 70 ++++++++++ apps/sim/app/api/tools/sqs/utils.ts | 40 ++++++ apps/sim/blocks/blocks/sqs.ts | 155 ++++++++++++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 29 ++++ apps/sim/package.json | 1 + apps/sim/tools/registry.ts | 2 + apps/sim/tools/sqs/index.ts | 3 + apps/sim/tools/sqs/send.ts | 91 +++++++++++++ apps/sim/tools/sqs/types.ts | 22 +++ bun.lock | 37 ++++++ 15 files changed, 547 insertions(+) create mode 100644 apps/docs/content/docs/en/tools/sqs.mdx create mode 100644 apps/sim/app/api/tools/sqs/send/route.ts create mode 100644 apps/sim/app/api/tools/sqs/utils.ts create mode 100644 apps/sim/blocks/blocks/sqs.ts create mode 100644 apps/sim/tools/sqs/index.ts create mode 100644 apps/sim/tools/sqs/send.ts create mode 100644 apps/sim/tools/sqs/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index da739b9273..eca760cf55 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -838,6 +838,35 @@ export const S3Icon = (props: SVGProps) => ( ) +export function SQSIcon(props: SVGProps) { + return ( + + + + + + + + ) +} + export function GoogleIcon(props: SVGProps) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index eae3993dc1..d8c1897013 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -90,6 +90,7 @@ import { ShopifyIcon, SlackIcon, SmtpIcon, + SQSIcon, SshIcon, STTIcon, StagehandIcon, @@ -215,6 +216,7 @@ export const blockTypeToIconMap: Record = { elevenlabs: ElevenLabsIcon, elasticsearch: ElasticsearchIcon, dynamodb: DynamoDBIcon, + sqs: SQSIcon, duckduckgo: DuckDuckGoIcon, dropbox: DropboxIcon, discord: DiscordIcon, diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index c90365fedf..752119460f 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -86,6 +86,7 @@ "shopify", "slack", "smtp", + "sqs", "ssh", "stagehand", "stagehand_agent", diff --git a/apps/docs/content/docs/en/tools/sqs.mdx b/apps/docs/content/docs/en/tools/sqs.mdx new file mode 100644 index 0000000000..a4c368b63f --- /dev/null +++ b/apps/docs/content/docs/en/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: Connect to Amazon SQS +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS eliminates the complexity and overhead associated with managing and operating message-oriented middleware, and empowers developers to focus on differentiating work. + +With Amazon SQS, you can: + +- **Send messages**: Publish messages to queues for asynchronous processing +- **Decouple applications**: Enable loose coupling between components of your system +- **Scale workloads**: Handle variable workloads without provisioning infrastructure +- **Ensure reliability**: Built-in redundancy and high availability +- **Support FIFO queues**: Maintain strict message ordering and exactly-once processing + +In Sim, the SQS integration enables your agents to send messages to Amazon SQS queues securely and programmatically. Supported operations include: + +- **Send Message**: Send messages to SQS queues with optional message group ID and deduplication ID for FIFO queues + +This integration allows your agents to automate message sending workflows without manual intervention. By connecting Sim with Amazon SQS, you can build agents that publish messages to queues within your workflows—all without handling queue infrastructure or connections. +{/* MANUAL-CONTENT-END */} + +## Usage Instructions + +Integrate Amazon SQS into the workflow. Can send messages to SQS queues. + +## Tools + +### `sqs_send` + +Send a message to an Amazon SQS queue + +#### Input + +| Parameter | Type | Required | Description | +| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `queueUrl` | string | Yes | Queue URL \(e.g., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | +| `data` | object | Yes | Message body to send as JSON object | +| `messageGroupId` | string | No | Message group ID \(optional\) | +| `messageDeduplicationId` | string | No | Message deduplication ID for FIFO queues \(optional\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ------ | --------------------------------------------------------- | +| `message` | string | Success or error message describing the operation outcome | +| `id` | string | Message ID | + +## Notes + +- Category: `tools` +- Type: `sqs` diff --git a/apps/sim/app/api/tools/sqs/send/route.ts b/apps/sim/app/api/tools/sqs/send/route.ts new file mode 100644 index 0000000000..402f5ca53c --- /dev/null +++ b/apps/sim/app/api/tools/sqs/send/route.ts @@ -0,0 +1,70 @@ +import { randomUUID } from 'crypto' +import { type NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' +import { createLogger } from '@/lib/logs/console/logger' +import { createSqsClient, sendMessage } from '../utils' + +const logger = createLogger('SQSSendMessageAPI') + +const SendMessageSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + queueUrl: z.string().min(1, 'Queue URL is required'), + messageGroupId: z.string().nullish(), + messageDeduplicationId: z.string().nullish(), + data: z.record(z.unknown()).refine((obj) => Object.keys(obj).length > 0, { + message: 'Data object must have at least one field', + }), +}) + +export async function POST(request: NextRequest) { + const requestId = randomUUID().slice(0, 8) + + try { + const body = await request.json() + const params = SendMessageSchema.parse(body) + + logger.info(`[${requestId}] Sending message to SQS queue ${params.queueUrl}`) + + const client = createSqsClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await sendMessage( + client, + params.queueUrl, + params.data, + params.messageGroupId, + params.messageDeduplicationId + ) + + logger.info(`[${requestId}] Message sent to SQS queue ${params.queueUrl}`) + + return NextResponse.json({ + message: `Message sent to SQS queue ${params.queueUrl}`, + id: result?.id, + }) + } finally { + client.destroy() + } + } catch (error) { + if (error instanceof z.ZodError) { + logger.warn(`[${requestId}] Invalid request data`, { + errors: error.errors, + }) + return NextResponse.json( + { error: 'Invalid request data', details: error.errors }, + { status: 400 } + ) + } + + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' + logger.error(`[${requestId}] SQS send message failed:`, error) + + return NextResponse.json({ error: `SQS send message failed: ${errorMessage}` }, { status: 500 }) + } +} diff --git a/apps/sim/app/api/tools/sqs/utils.ts b/apps/sim/app/api/tools/sqs/utils.ts new file mode 100644 index 0000000000..e3853af130 --- /dev/null +++ b/apps/sim/app/api/tools/sqs/utils.ts @@ -0,0 +1,40 @@ +import { SendMessageCommand, type SendMessageCommandOutput, SQSClient } from '@aws-sdk/client-sqs' +import type { SqsConnectionConfig } from '@/tools/sqs/types' + +export function createSqsClient(config: SqsConnectionConfig): SQSClient { + return new SQSClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} + +export async function sendMessage( + client: SQSClient, + queueUrl: string, + data: Record, + messageGroupId?: string | null, + messageDeduplicationId?: string | null +): Promise | null> { + const command = new SendMessageCommand({ + QueueUrl: queueUrl, + MessageBody: JSON.stringify(data), + MessageGroupId: messageGroupId ?? undefined, + ...(messageDeduplicationId ? { MessageDeduplicationId: messageDeduplicationId } : {}), + }) + + const response = await client.send(command) + return parseSendMessageResponse(response) +} + +function parseSendMessageResponse( + response: SendMessageCommandOutput +): Record | null { + if (!response) { + return null + } + + return { id: response.MessageId } +} diff --git a/apps/sim/blocks/blocks/sqs.ts b/apps/sim/blocks/blocks/sqs.ts new file mode 100644 index 0000000000..72f6ccacdc --- /dev/null +++ b/apps/sim/blocks/blocks/sqs.ts @@ -0,0 +1,155 @@ +import { SQSIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import type { SqsResponse } from '@/tools/sqs/types' + +export const SQSBlock: BlockConfig = { + type: 'sqs', + name: 'Amazon SQS', + description: 'Connect to Amazon SQS', + longDescription: 'Integrate Amazon SQS into the workflow. Can send messages to SQS queues.', + docsLink: 'https://docs.sim.ai/tools/sqs', + category: 'tools', + bgColor: 'linear-gradient(45deg, #2E27AD 0%, #527FFF 100%)', + icon: SQSIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [{ label: 'Send Message', id: 'send' }], + value: () => 'send', + }, + { + id: 'region', + title: 'AWS Region', + type: 'short-input', + placeholder: 'us-east-1', + required: true, + }, + { + id: 'accessKeyId', + title: 'AWS Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + password: true, + required: true, + }, + { + id: 'secretAccessKey', + title: 'AWS Secret Access Key', + type: 'short-input', + placeholder: 'Your secret access key', + password: true, + required: true, + }, + { + id: 'queueUrl', + title: 'Queue URL', + type: 'short-input', + placeholder: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue', + required: true, + }, + // Data field for send message operation + { + id: 'messageGroupId', + title: 'Message Group ID (optional)', + type: 'short-input', + placeholder: '5FAB0F0B-30C6-4427-9407-5634F4A3984A', + condition: { field: 'operation', value: 'send' }, + required: false, + }, + { + id: 'messageDeduplicationId', + title: 'Message Deduplication ID (optional)', + type: 'short-input', + placeholder: '5FAB0F0B-30C6-4427-9407-5634F4A3984A', + condition: { field: 'operation', value: 'send' }, + required: false, + }, + { + id: 'data', + title: 'Data (JSON)', + type: 'code', + placeholder: '{\n "name": "John Doe",\n "email": "john@example.com",\n "active": true\n}', + condition: { field: 'operation', value: 'send' }, + required: true, + }, + ], + tools: { + access: ['sqs_send'], + config: { + tool: (params) => { + switch (params.operation) { + case 'send': + return 'sqs_send' + default: + throw new Error(`Invalid SQS operation: ${params.operation}`) + } + }, + params: (params) => { + const { operation, data, messageGroupId, messageDeduplicationId, ...rest } = params + + // Parse JSON fields + const parseJson = (value: unknown, fieldName: string) => { + if (!value) return undefined + if (typeof value === 'object') return value + if (typeof value === 'string' && value.trim()) { + try { + return JSON.parse(value) + } catch (parseError) { + const errorMsg = + parseError instanceof Error ? parseError.message : 'Unknown JSON error' + throw new Error(`Invalid JSON in ${fieldName}: ${errorMsg}`) + } + } + return undefined + } + + const parsedData = parseJson(data, 'data') + + // Build connection config + const connectionConfig = { + region: rest.region, + accessKeyId: rest.accessKeyId, + secretAccessKey: rest.secretAccessKey, + } + + // Build params object + const result: Record = { ...connectionConfig } + + if (rest.queueUrl) result.queueUrl = rest.queueUrl + if (messageGroupId) result.messageGroupId = messageGroupId + if (messageDeduplicationId) result.messageDeduplicationId = messageDeduplicationId + if (parsedData !== undefined) result.data = parsedData + + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'SQS operation to perform' }, + region: { type: 'string', description: 'AWS region' }, + accessKeyId: { type: 'string', description: 'AWS access key ID' }, + secretAccessKey: { type: 'string', description: 'AWS secret access key' }, + queueUrl: { type: 'string', description: 'SQS queue URL' }, + messageGroupId: { + type: 'string', + description: 'Message group ID (optional)', + }, + messageDeduplicationId: { + type: 'string', + description: 'Message deduplication ID (optional)', + }, + data: { type: 'json', description: 'Data for send message operation' }, + }, + outputs: { + message: { + type: 'string', + description: 'Success or error message describing the operation outcome', + }, + id: { + type: 'string', + description: 'Message ID', + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index b49f581516..3d87a6c49b 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -137,6 +137,7 @@ import { ZendeskBlock } from '@/blocks/blocks/zendesk' import { ZepBlock } from '@/blocks/blocks/zep' import { ZoomBlock } from '@/blocks/blocks/zoom' import type { BlockConfig } from '@/blocks/types' +import { SQSBlock } from './blocks/sqs' // Registry of all available blocks, alphabetically sorted export const registry: Record = { @@ -226,6 +227,7 @@ export const registry: Record = { pylon: PylonBlock, qdrant: QdrantBlock, rds: RDSBlock, + sqs: SQSBlock, dynamodb: DynamoDBBlock, reddit: RedditBlock, resend: ResendBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index da739b9273..6d7d5a7083 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -3902,6 +3902,35 @@ export function DynamoDBIcon(props: SVGProps) { ) } +export function SQSIcon(props: SVGProps) { + return ( + + + + + + + + ) +} + export function McpIcon(props: SVGProps) { return ( = { @@ -2327,6 +2328,7 @@ export const tools: Record = { salesforce_query_more: salesforceQueryMoreTool, salesforce_describe_object: salesforceDescribeObjectTool, salesforce_list_objects: salesforceListObjectsTool, + sqs_send: sqsSendTool, pylon_list_issues: pylonListIssuesTool, pylon_create_issue: pylonCreateIssueTool, pylon_get_issue: pylonGetIssueTool, diff --git a/apps/sim/tools/sqs/index.ts b/apps/sim/tools/sqs/index.ts new file mode 100644 index 0000000000..7f034b487d --- /dev/null +++ b/apps/sim/tools/sqs/index.ts @@ -0,0 +1,3 @@ +import { sendTool } from './send' + +export const sqsSendTool = sendTool diff --git a/apps/sim/tools/sqs/send.ts b/apps/sim/tools/sqs/send.ts new file mode 100644 index 0000000000..46836fe16d --- /dev/null +++ b/apps/sim/tools/sqs/send.ts @@ -0,0 +1,91 @@ +import type { SqsSendMessageParams, SqsSendMessageResponse } from '@/tools/sqs/types' +import type { ToolConfig } from '@/tools/types' + +export const sendTool: ToolConfig = { + id: 'sqs_send', + name: 'SQS Send Message', + description: 'Send a message to an Amazon SQS queue', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + queueUrl: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Queue URL', + }, + data: { + type: 'object', + required: true, + visibility: 'user-or-llm', + description: 'Message body to send', + }, + messageGroupId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Message group ID (optional)', + }, + messageDeduplicationId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Message deduplication ID (optional)', + }, + }, + + request: { + url: '/api/tools/sqs/send', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + queueUrl: params.queueUrl, + data: params.data, + messageGroupId: params.messageGroupId, + messageDeduplicationId: params.messageDeduplicationId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'SQS send message failed') + } + + return { + success: true, + output: { + message: data.message || 'SQS send message executed successfully', + id: data.id || '', + }, + error: undefined, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + id: { type: 'string', description: 'Message ID' }, + }, +} diff --git a/apps/sim/tools/sqs/types.ts b/apps/sim/tools/sqs/types.ts new file mode 100644 index 0000000000..a74e433ab9 --- /dev/null +++ b/apps/sim/tools/sqs/types.ts @@ -0,0 +1,22 @@ +import type { ToolResponse } from '@/tools/types' + +export interface SqsConnectionConfig { + region: string + accessKeyId: string + secretAccessKey: string +} + +export interface SqsSendMessageParams extends SqsConnectionConfig { + queueUrl: string + data: Record + messageGroupId?: string | null + messageDeduplicationId?: string | null +} + +export interface SqsBaseResponse extends ToolResponse { + output: { message: string; id?: string } + error?: string +} + +export interface SqsSendMessageResponse extends SqsBaseResponse {} +export interface SqsResponse extends SqsBaseResponse {} diff --git a/bun.lock b/bun.lock index 687be5911f..e31b8934e6 100644 --- a/bun.lock +++ b/bun.lock @@ -75,6 +75,7 @@ "@aws-sdk/client-dynamodb": "3.940.0", "@aws-sdk/client-rds-data": "3.940.0", "@aws-sdk/client-s3": "^3.779.0", + "@aws-sdk/client-sqs": "3.947.0", "@aws-sdk/lib-dynamodb": "3.940.0", "@aws-sdk/s3-request-presigner": "^3.779.0", "@azure/communication-email": "1.0.0", @@ -336,6 +337,8 @@ "@aws-sdk/client-sesv2": ["@aws-sdk/client-sesv2@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.948.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7Sl8bRFFLAEQdlvTlaSNFlUHjD+B3N+gbhpS+vH/IlETSmn3fMm4b0Bvve8CWs8jUCctx8nDwXh+0lOWgNDQXw=="], + "@aws-sdk/client-sqs": ["@aws-sdk/client-sqs@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-sqs": "3.946.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-8tzFyYGAAnQg+G9eB5zAe0oEo+MJMZ3YEk+8EL4uf2zG5wKxJvTBJZr6U9I1CEXYUde374OyLMyKng+sWyN+wg=="], + "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], "@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], @@ -378,6 +381,8 @@ "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DS2tm5YBKhPW2PthrRBDr6eufChbwXe0NjtTZcYDfUCXf0OR+W6cIqyKguwHMJ+IyYdey30AfVw9/Lb5KB8U8A=="], + "@aws-sdk/middleware-sdk-sqs": ["@aws-sdk/middleware-sdk-sqs@3.946.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-+KedlcXUqA1Bdafvw264SWvwyHYvFxn47y831tEKc85fp5VF5LGE9uMlU13hsWySftLmDd/ZFwSQI6RN2zSpAg=="], + "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA=="], "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], @@ -3482,6 +3487,14 @@ "@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="], + "@aws-sdk/client-sqs/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.947.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.947.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.947.0", "@aws-sdk/credential-provider-web-identity": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-S0Zqebr71KyrT6J4uYPhwV65g4V5uDPHnd7dt2W34FcyPu+hVC7Hx4MFmsPyVLeT5cMCkkZvmY3kAoEzgUPJJg=="], + + "@aws-sdk/client-sqs/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="], + + "@aws-sdk/client-sqs/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="], + "@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="], "@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="], @@ -4036,6 +4049,18 @@ "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.947.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.947.0", "@aws-sdk/credential-provider-web-identity": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-A2ZUgJUJZERjSzvCi2NR/hBVbVkTXPD0SdKcR/aITb30XwF+n3T963b+pJl90qhOspoy7h0IVYNR7u5Nr9tJdQ=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.947.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.947.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-NktnVHTGaUMaozxycYrepvb3yfFquHTQ53lt6hBEVjYBzK3C4tVz0siUpr+5RMGLSiZ5bLBp2UjJPgwx4i4waQ=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gokm/e/YHiHLrZgLq4j8tNAn8RJDPbIcglFRKgy08q8DmAqHQ8MXAKW3eS0QjAuRXU9mcMmUo1NrX6FRNBCCPw=="], + "@browserbasehq/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], "@browserbasehq/sdk/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], @@ -4404,6 +4429,16 @@ "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-u7M3hazcB7aJiVwosNdJRbIJDzbwQ861NTtl6S0HmvWpixaVb7iyhJZWg8/plyUznboZGBm7JVEdxtxv3u0bTA=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-sDwcO8SP290WSErY1S8pz8hTafeghKmmWjNVks86jDK30wx62CfazOTeU70IpWgrUBEygyXk/zPogHsUMbW2Rg=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-X/DyB8GuK44rsE89Tn5+s542B3PhGbXQSgV8lvqHDzvicwCt0tWny6790st6CPETrVVV2K3oJMfG5U3/jAmaZA=="], + + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], + "@browserbasehq/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@browserbasehq/sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -4496,6 +4531,8 @@ "@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="], + "@aws-sdk/client-sqs/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.947.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw=="], + "@trigger.dev/core/socket.io/engine.io/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], "lint-staged/listr2/cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], From 57b6bc3684acbad2068600a7ac8c915463950b2e Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 15:28:31 -0800 Subject: [PATCH 03/34] feat(i18n): update translations (#2321) Co-authored-by: waleedlatif1 --- apps/docs/content/docs/de/tools/sqs.mdx | 63 +++++++++++++++++++++++++ apps/docs/content/docs/es/tools/sqs.mdx | 63 +++++++++++++++++++++++++ apps/docs/content/docs/fr/tools/sqs.mdx | 63 +++++++++++++++++++++++++ apps/docs/content/docs/ja/tools/sqs.mdx | 63 +++++++++++++++++++++++++ apps/docs/content/docs/zh/tools/sqs.mdx | 63 +++++++++++++++++++++++++ apps/docs/i18n.lock | 22 +++++++++ 6 files changed, 337 insertions(+) create mode 100644 apps/docs/content/docs/de/tools/sqs.mdx create mode 100644 apps/docs/content/docs/es/tools/sqs.mdx create mode 100644 apps/docs/content/docs/fr/tools/sqs.mdx create mode 100644 apps/docs/content/docs/ja/tools/sqs.mdx create mode 100644 apps/docs/content/docs/zh/tools/sqs.mdx diff --git a/apps/docs/content/docs/de/tools/sqs.mdx b/apps/docs/content/docs/de/tools/sqs.mdx new file mode 100644 index 0000000000..912f49ceb3 --- /dev/null +++ b/apps/docs/content/docs/de/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: Verbindung zu Amazon SQS +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) ist ein vollständig verwalteter Message-Queuing-Dienst, der es ermöglicht, Microservices, verteilte Systeme und serverlose Anwendungen zu entkoppeln und zu skalieren. SQS beseitigt die Komplexität und den Aufwand, die mit der Verwaltung und dem Betrieb von nachrichtenorientierter Middleware verbunden sind, und ermöglicht Entwicklern, sich auf differenzierende Arbeit zu konzentrieren. + +Mit Amazon SQS können Sie: + +- **Nachrichten senden**: Veröffentlichen Sie Nachrichten in Warteschlangen für asynchrone Verarbeitung +- **Anwendungen entkoppeln**: Ermöglichen Sie eine lose Kopplung zwischen Komponenten Ihres Systems +- **Workloads skalieren**: Bewältigen Sie variable Arbeitslasten ohne Bereitstellung von Infrastruktur +- **Zuverlässigkeit gewährleisten**: Eingebaute Redundanz und hohe Verfügbarkeit +- **FIFO-Warteschlangen unterstützen**: Strikte Nachrichtenreihenfolge und genau einmalige Verarbeitung beibehalten + +In Sim ermöglicht die SQS-Integration Ihren Agenten, Nachrichten sicher und programmatisch an Amazon SQS-Warteschlangen zu senden. Unterstützte Operationen umfassen: + +- **Nachricht senden**: Senden Sie Nachrichten an SQS-Warteschlangen mit optionaler Nachrichtengruppen-ID und Deduplizierungs-ID für FIFO-Warteschlangen + +Diese Integration ermöglicht es Ihren Agenten, Workflows zum Senden von Nachrichten ohne manuelle Eingriffe zu automatisieren. Durch die Verbindung von Sim mit Amazon SQS können Sie Agenten erstellen, die Nachrichten innerhalb Ihrer Workflows in Warteschlangen veröffentlichen – alles ohne Verwaltung der Warteschlangen-Infrastruktur oder Verbindungen. +{/* MANUAL-CONTENT-END */} + +## Nutzungsanweisungen + +Integrieren Sie Amazon SQS in den Workflow. Kann Nachrichten an SQS-Warteschlangen senden. + +## Tools + +### `sqs_send` + +Eine Nachricht an eine Amazon SQS-Warteschlange senden + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| ------------------------ | ------ | ------------ | ---------------------------------------------------------------------------- | +| `region` | string | Ja | AWS-Region (z.B. us-east-1) | +| `accessKeyId` | string | Ja | AWS-Zugriffsschlüssel-ID | +| `secretAccessKey` | string | Ja | AWS-Geheimzugriffsschlüssel | +| `queueUrl` | string | Ja | Warteschlangen-URL (z.B. https://sqs.us-east-1.amazonaws.com/123456789012/my-queue) | +| `data` | object | Ja | Nachrichteninhalt als JSON-Objekt zu senden | +| `messageGroupId` | string | Nein | Nachrichtengruppen-ID (optional) | +| `messageDeduplicationId` | string | Nein | Nachrichten-Deduplizierungs-ID für FIFO-Warteschlangen (optional) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ------ | -------------------------------------------------------- | +| `message` | string | Erfolgs- oder Fehlermeldung, die das Ergebnis der Operation beschreibt | +| `id` | string | Nachrichten-ID | + +## Hinweise + +- Kategorie: `tools` +- Typ: `sqs` diff --git a/apps/docs/content/docs/es/tools/sqs.mdx b/apps/docs/content/docs/es/tools/sqs.mdx new file mode 100644 index 0000000000..cfe1dd8368 --- /dev/null +++ b/apps/docs/content/docs/es/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: Conectar a Amazon SQS +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) es un servicio de cola de mensajes completamente administrado que permite desacoplar y escalar microservicios, sistemas distribuidos y aplicaciones sin servidor. SQS elimina la complejidad y la sobrecarga asociadas con la gestión y operación de middleware orientado a mensajes, y permite a los desarrolladores centrarse en el trabajo diferenciador. + +Con Amazon SQS, puedes: + +- **Enviar mensajes**: Publicar mensajes en colas para procesamiento asíncrono +- **Desacoplar aplicaciones**: Permitir un acoplamiento flexible entre los componentes de tu sistema +- **Escalar cargas de trabajo**: Manejar cargas de trabajo variables sin aprovisionar infraestructura +- **Garantizar fiabilidad**: Redundancia incorporada y alta disponibilidad +- **Soportar colas FIFO**: Mantener un orden estricto de mensajes y procesamiento exactamente una vez + +En Sim, la integración con SQS permite a tus agentes enviar mensajes a las colas de Amazon SQS de forma segura y programática. Las operaciones compatibles incluyen: + +- **Enviar mensaje**: Enviar mensajes a colas SQS con ID de grupo de mensajes opcional e ID de deduplicación para colas FIFO + +Esta integración permite a tus agentes automatizar flujos de trabajo de envío de mensajes sin intervención manual. Al conectar Sim con Amazon SQS, puedes crear agentes que publiquen mensajes en colas dentro de tus flujos de trabajo, todo sin tener que gestionar la infraestructura o las conexiones de las colas. +{/* MANUAL-CONTENT-END */} + +## Instrucciones de uso + +Integra Amazon SQS en el flujo de trabajo. Puede enviar mensajes a colas SQS. + +## Herramientas + +### `sqs_send` + +Enviar un mensaje a una cola de Amazon SQS + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | +| `region` | string | Sí | Región de AWS \(p. ej., us-east-1\) | +| `accessKeyId` | string | Sí | ID de clave de acceso de AWS | +| `secretAccessKey` | string | Sí | Clave de acceso secreta de AWS | +| `queueUrl` | string | Sí | URL de la cola \(p. ej., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | +| `data` | object | Sí | Cuerpo del mensaje para enviar como objeto JSON | +| `messageGroupId` | string | No | ID de grupo de mensajes \(opcional\) | +| `messageDeduplicationId` | string | No | ID de deduplicación de mensajes para colas FIFO \(opcional\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ------ | --------------------------------------------------------- | +| `message` | string | Mensaje de éxito o error que describe el resultado de la operación | +| `id` | string | ID del mensaje | + +## Notas + +- Categoría: `tools` +- Tipo: `sqs` diff --git a/apps/docs/content/docs/fr/tools/sqs.mdx b/apps/docs/content/docs/fr/tools/sqs.mdx new file mode 100644 index 0000000000..656f0cc3f1 --- /dev/null +++ b/apps/docs/content/docs/fr/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: Se connecter à Amazon SQS +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) est un service de file d'attente de messages entièrement géré qui permet de découpler et de mettre à l'échelle des microservices, des systèmes distribués et des applications sans serveur. SQS élimine la complexité et les frais généraux associés à la gestion et à l'exploitation d'un middleware orienté messages, et permet aux développeurs de se concentrer sur un travail différenciant. + +Avec Amazon SQS, vous pouvez : + +- **Envoyer des messages** : publier des messages dans des files d'attente pour un traitement asynchrone +- **Découpler des applications** : permettre un couplage souple entre les composants de votre système +- **Mettre à l'échelle les charges de travail** : gérer des charges de travail variables sans provisionner d'infrastructure +- **Assurer la fiabilité** : redondance intégrée et haute disponibilité +- **Prendre en charge les files d'attente FIFO** : maintenir un ordre strict des messages et un traitement exactement une fois + +Dans Sim, l'intégration SQS permet à vos agents d'envoyer des messages aux files d'attente Amazon SQS de manière sécurisée et programmatique. Les opérations prises en charge comprennent : + +- **Envoi de message** : envoyer des messages aux files d'attente SQS avec un ID de groupe de messages facultatif et un ID de déduplication pour les files d'attente FIFO + +Cette intégration permet à vos agents d'automatiser les flux de travail d'envoi de messages sans intervention manuelle. En connectant Sim à Amazon SQS, vous pouvez créer des agents qui publient des messages dans des files d'attente au sein de vos flux de travail, le tout sans avoir à gérer l'infrastructure ou les connexions des files d'attente. +{/* MANUAL-CONTENT-END */} + +## Instructions d'utilisation + +Intégrez Amazon SQS dans le flux de travail. Peut envoyer des messages aux files d'attente SQS. + +## Outils + +### `sqs_send` + +Envoyer un message à une file d'attente Amazon SQS + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| ------------------------ | ------ | ----------- | ----------------------------------------------------------------------------- | +| `region` | string | Oui | Région AWS (par ex., us-east-1) | +| `accessKeyId` | string | Oui | ID de clé d'accès AWS | +| `secretAccessKey` | string | Oui | Clé d'accès secrète AWS | +| `queueUrl` | string | Oui | URL de la file d'attente (par ex., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue) | +| `data` | object | Oui | Corps du message à envoyer sous forme d'objet JSON | +| `messageGroupId` | string | Non | ID de groupe de messages (facultatif) | +| `messageDeduplicationId` | string | Non | ID de déduplication de message pour les files d'attente FIFO (facultatif) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ------ | --------------------------------------------------------- | +| `message` | chaîne | Message de succès ou d'erreur décrivant le résultat de l'opération | +| `id` | chaîne | ID du message | + +## Notes + +- Catégorie : `tools` +- Type : `sqs` diff --git a/apps/docs/content/docs/ja/tools/sqs.mdx b/apps/docs/content/docs/ja/tools/sqs.mdx new file mode 100644 index 0000000000..04e8232744 --- /dev/null +++ b/apps/docs/content/docs/ja/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: Amazon SQSに接続 +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/)は、マイクロサービス、分散システム、サーバーレスアプリケーションの分離とスケーリングを可能にする完全マネージド型のメッセージキューイングサービスです。SQSは、メッセージ指向のミドルウェアの管理と運用に関連する複雑さとオーバーヘッドを排除し、開発者が差別化作業に集中できるようにします。 + +Amazon SQSでは、以下のことが可能です: + +- **メッセージの送信**:非同期処理のためにキューにメッセージを公開 +- **アプリケーションの分離**:システムのコンポーネント間の疎結合を実現 +- **ワークロードのスケーリング**:インフラストラクチャをプロビジョニングせずに変動するワークロードを処理 +- **信頼性の確保**:組み込みの冗長性と高可用性 +- **FIFOキューのサポート**:厳密なメッセージ順序と完全に一度だけの処理を維持 + +Simでは、SQS統合により、エージェントがAmazon SQSキューにメッセージを安全にプログラムで送信できるようになります。サポートされている操作には以下が含まれます: + +- **メッセージ送信**:FIFOキュー用のオプションのメッセージグループIDと重複排除IDを使用してSQSキューにメッセージを送信 + +この統合により、エージェントは手動介入なしでメッセージ送信ワークフローを自動化できます。SimとAmazon SQSを接続することで、キューインフラストラクチャや接続を処理することなく、ワークフロー内でキューにメッセージを公開するエージェントを構築できます。 +{/* MANUAL-CONTENT-END */} + +## 使用手順 + +Amazon SQSをワークフローに統合します。SQSキューにメッセージを送信できます。 + +## ツール + +### `sqs_send` + +Amazon SQSキューにメッセージを送信 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | +| `region` | string | はい | AWSリージョン(例:us-east-1) | +| `accessKeyId` | string | はい | AWSアクセスキーID | +| `secretAccessKey` | string | はい | AWSシークレットアクセスキー | +| `queueUrl` | string | はい | キューURL(例:https://sqs.us-east-1.amazonaws.com/123456789012/my-queue)| +| `data` | object | はい | JSONオブジェクトとして送信するメッセージ本文 | +| `messageGroupId` | string | いいえ | メッセージグループID(オプション) | +| `messageDeduplicationId` | string | いいえ | FIFOキュー用のメッセージ重複排除ID(オプション) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ------ | --------------------------------------------------------- | +| `message` | string | 操作結果を説明する成功またはエラーメッセージ | +| `id` | string | メッセージID | + +## 注意事項 + +- カテゴリー: `tools` +- タイプ: `sqs` diff --git a/apps/docs/content/docs/zh/tools/sqs.mdx b/apps/docs/content/docs/zh/tools/sqs.mdx new file mode 100644 index 0000000000..7ba2785a98 --- /dev/null +++ b/apps/docs/content/docs/zh/tools/sqs.mdx @@ -0,0 +1,63 @@ +--- +title: Amazon SQS +description: 连接到 Amazon SQS +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card"; + + + +{/* MANUAL-CONTENT-START:intro */} +[Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) 是一项完全托管的消息队列服务,可帮助您解耦和扩展微服务、分布式系统和无服务器应用程序。SQS 消除了与管理和操作面向消息的中间件相关的复杂性和开销,使开发人员能够专注于差异化工作。 + +使用 Amazon SQS,您可以: + +- **发送消息**:将消息发布到队列以进行异步处理 +- **解耦应用程序**:实现系统组件之间的松耦合 +- **扩展工作负载**:处理可变工作负载,无需预置基础设施 +- **确保可靠性**:内置冗余和高可用性 +- **支持 FIFO 队列**:保持严格的消息顺序和精确的一次性处理 + +在 Sim 中,SQS 集成使您的代理能够安全且以编程方式将消息发送到 Amazon SQS 队列。支持的操作包括: + +- **发送消息**:将消息发送到 SQS 队列,并为 FIFO 队列提供可选的消息组 ID 和去重 ID + +此集成允许您的代理自动化消息发送工作流,无需人工干预。通过将 Sim 与 Amazon SQS 连接,您可以构建代理,在工作流中将消息发布到队列,而无需处理队列基础设施或连接。 +{/* MANUAL-CONTENT-END */} + +## 使用说明 + +将 Amazon SQS 集成到工作流中。可以将消息发送到 SQS 队列。 + +## 工具 + +### `sqs_send` + +向 Amazon SQS 队列发送消息 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| ------------------------ | ------ | ------ | -------------------------------------------------------------------------- | +| `region` | string | 是 | AWS 区域 \(例如,us-east-1\) | +| `accessKeyId` | string | 是 | AWS 访问密钥 ID | +| `secretAccessKey` | string | 是 | AWS 秘密访问密钥 | +| `queueUrl` | string | 是 | 队列 URL \(例如,https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | +| `data` | object | 是 | 要作为 JSON 对象发送的消息正文 | +| `messageGroupId` | string | 否 | 消息组 ID \(可选\) | +| `messageDeduplicationId` | string | 否 | FIFO 队列的消息去重 ID \(可选\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ------ | --------------------------------------------------------- | +| `message` | string | 描述操作结果的成功或错误信息 | +| `id` | string | 消息 ID | + +## 注意事项 + +- 类别: `tools` +- 类型: `sqs` diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index b740d582f3..385b5cbe4b 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -49305,3 +49305,25 @@ checksums: content/9: 7a3be8a3771ee428ecf09008e42c0e2e content/10: 42e4caf9b036a8d7726a8968f3ed201f content/11: e74f8ee79105babdaa8dfec520ecdf74 + 01bda2a6417895b3b24a3d2b543866d4: + meta/title: 55272c40df2a877093c8470e52102e87 + meta/description: 13e8a6591a8addf009cb647bb7ee6a0d + content/0: 19c5610b4392aadcf63d11fff6261b71 + content/1: 722f06242bbde726fd9de48cf1762e21 + content/2: da04d549734a9cf9c8cc168dbd6952dc + content/3: ecde46402d67144e99794c51b616c17d + content/4: 8884d8cca8ee6de94be5d8116e2f94b6 + content/5: 3b6cc1660e95dc03733da604d98f19b9 + content/6: 2167786106b3d684b5175827be6b3a1f + content/7: 3271375c7c99de5bdf13fad0b98b466d + content/8: 821e6394b0a953e2b0842b04ae8f3105 + content/9: 88b0ee08769002bb9b22b4683e7a8e4c + content/10: 9c8aa3f09c9b2bd50ea4cdff3598ea4e + content/11: b1a2d0fd1320fb6a73e3fda153b9c7ae + content/12: cba5245faf73a6067d5720b824e1bef0 + content/13: 371d0e46b4bd2c23f559b8bc112f6955 + content/14: 16cc4f2c3e461466e347399b60e4b130 + content/15: bcadfc362b69078beee0088e5936c98b + content/16: 44bff30d972517dcf6be3dd00a8d7e4a + content/17: b3f310d5ef115bea5a8b75bf25d7ea9a + content/18: a4748f8ce0a4667675ca03e4d9fef87b From 31b795f8b1e3e32b4d61f31f67f1edfe40975507 Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 17:07:25 -0800 Subject: [PATCH 04/34] fix(tools): fixed webflow limit and offset params (#2323) --- apps/sim/tools/webflow/list_items.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/tools/webflow/list_items.ts b/apps/sim/tools/webflow/list_items.ts index 985b5b28d1..7cc092c325 100644 --- a/apps/sim/tools/webflow/list_items.ts +++ b/apps/sim/tools/webflow/list_items.ts @@ -44,10 +44,10 @@ export const webflowListItemsTool: ToolConfig Date: Thu, 11 Dec 2025 18:15:37 -0800 Subject: [PATCH 05/34] fix(mistral): remove wrapped output from mistral parse for kb parsing pdfs (#2326) --- apps/sim/tools/mistral/parser.ts | 51 ++++++++++++++------------------ 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/apps/sim/tools/mistral/parser.ts b/apps/sim/tools/mistral/parser.ts index 33a70e85be..70547a9061 100644 --- a/apps/sim/tools/mistral/parser.ts +++ b/apps/sim/tools/mistral/parser.ts @@ -258,7 +258,11 @@ export const mistralParserTool: ToolConfig 0) { - content = ocrResult.pages + content = mistralData.pages .map((page: any) => (page && typeof page.markdown === 'string' ? page.markdown : '')) .filter(Boolean) .join('\n\n') } else { logger.warn('No pages found in OCR result, returning raw response') - content = JSON.stringify(ocrResult, null, 2) + content = JSON.stringify(mistralData, null, 2) } - // Process based on requested result type if (resultType === 'text') { - // Strip markdown formatting content = content .replace(/##*\s/g, '') // Remove markdown headers .replace(/\*\*/g, '') // Remove bold markers .replace(/\*/g, '') // Remove italic markers .replace(/\n{3,}/g, '\n\n') // Normalize newlines } else if (resultType === 'json') { - // Return the structured data as JSON string - content = JSON.stringify(ocrResult, null, 2) + content = JSON.stringify(mistralData, null, 2) } - // Extract file information with proper validation let fileName = 'document.pdf' let fileType = 'pdf' @@ -333,27 +331,24 @@ export const mistralParserTool: ToolConfig Date: Thu, 11 Dec 2025 18:22:16 -0800 Subject: [PATCH 06/34] fix(kb): handle larger files in the kb (#2324) * fix(kb): handle larger files in the kb * fixed images on login page --- apps/sim/app/(landing)/components/nav/nav.tsx | 1 + .../app/workspace/[workspaceId]/knowledge/[id]/base.tsx | 2 +- .../knowledge/hooks/use-knowledge-upload.ts | 9 ++++----- apps/sim/lib/core/security/csp.ts | 2 +- apps/sim/lib/knowledge/documents/service.ts | 2 +- apps/sim/lib/uploads/utils/file-utils.ts | 9 ++++++++- apps/sim/proxy.ts | 4 +++- 7 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/sim/app/(landing)/components/nav/nav.tsx b/apps/sim/app/(landing)/components/nav/nav.tsx index 1725c2b164..48852e3748 100644 --- a/apps/sim/app/(landing)/components/nav/nav.tsx +++ b/apps/sim/app/(landing)/components/nav/nav.tsx @@ -135,6 +135,7 @@ export default function Nav({ hideAuthButtons = false, variant = 'landing' }: Na priority loading='eager' quality={100} + unoptimized /> ) : ( { const now = new Date() - const DEAD_PROCESS_THRESHOLD_MS = 150 * 1000 + const DEAD_PROCESS_THRESHOLD_MS = 600 * 1000 // 10 minutes const staleDocuments = documents.filter((doc) => { if (doc.processingStatus !== 'processing' || !doc.processingStartedAt) { diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload.ts index 96c85cfae2..d0deef22b5 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload.ts +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/hooks/use-knowledge-upload.ts @@ -423,6 +423,10 @@ export function useKnowledgeUpload(options: UseKnowledgeUploadOptions = {}) { return await uploadFileInChunks(file, presignedData, timeoutMs, fileIndex) } + if (presignedOverride?.directUploadSupported && presignedOverride.presignedUrl) { + return await uploadFileDirectly(file, presignedOverride, timeoutMs, controller, fileIndex) + } + return await uploadFileThroughAPI(file, timeoutMs) } finally { clearTimeout(timeoutId) @@ -510,7 +514,6 @@ export function useKnowledgeUpload(options: UseKnowledgeUploadOptions = {}) { if (event.lengthComputable && fileIndex !== undefined && !isCompleted) { const percentComplete = Math.round((event.loaded / event.total) * 100) setUploadProgress((prev) => { - // Only update if this file is still uploading if (prev.fileStatuses?.[fileIndex]?.status === 'uploading') { return { ...prev, @@ -638,7 +641,6 @@ export function useKnowledgeUpload(options: UseKnowledgeUploadOptions = {}) { }) if (!partUrlsResponse.ok) { - // Abort the multipart upload if we can't get URLs await fetch('/api/files/multipart?action=abort', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -822,9 +824,6 @@ export function useKnowledgeUpload(options: UseKnowledgeUploadOptions = {}) { } } - /** - * Upload files using batch presigned URLs (works for both S3 and Azure Blob) - */ /** * Uploads files in batches using presigned URLs */ diff --git a/apps/sim/lib/core/security/csp.ts b/apps/sim/lib/core/security/csp.ts index 01ce111f14..5e379b5901 100644 --- a/apps/sim/lib/core/security/csp.ts +++ b/apps/sim/lib/core/security/csp.ts @@ -153,7 +153,7 @@ export function generateRuntimeCSP(): string { default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://assets.onedollarstats.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; - img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com ${brandLogoDomain} ${brandFaviconDomain}; + img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.s3.amazonaws.com https://s3.amazonaws.com https://*.amazonaws.com https://*.blob.core.windows.net https://github.com/* ${brandLogoDomain} ${brandFaviconDomain}; media-src 'self' blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://api.browser-use.com https://api.exa.ai https://api.firecrawl.dev https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://api.github.com https://github.com/* https://*.atlassian.com https://*.supabase.co https://collector.onedollarstats.com ${dynamicDomainsStr}; diff --git a/apps/sim/lib/knowledge/documents/service.ts b/apps/sim/lib/knowledge/documents/service.ts index e79c9c568b..c9ff612823 100644 --- a/apps/sim/lib/knowledge/documents/service.ts +++ b/apps/sim/lib/knowledge/documents/service.ts @@ -1089,7 +1089,7 @@ export async function markDocumentAsFailedTimeout( ): Promise<{ success: boolean; processingDuration: number }> { const now = new Date() const processingDuration = now.getTime() - processingStartedAt.getTime() - const DEAD_PROCESS_THRESHOLD_MS = 150 * 1000 + const DEAD_PROCESS_THRESHOLD_MS = 600 * 1000 // 10 minutes if (processingDuration <= DEAD_PROCESS_THRESHOLD_MS) { throw new Error('Document has not been processing long enough to be considered dead') diff --git a/apps/sim/lib/uploads/utils/file-utils.ts b/apps/sim/lib/uploads/utils/file-utils.ts index 946ed02f36..4a1876f1a7 100644 --- a/apps/sim/lib/uploads/utils/file-utils.ts +++ b/apps/sim/lib/uploads/utils/file-utils.ts @@ -278,6 +278,7 @@ export function validateKnowledgeBaseFile( /** * Extract storage key from a file path + * Handles URLs like /api/files/serve/s3/key or /api/files/serve/blob/key */ export function extractStorageKey(filePath: string): string { let pathWithoutQuery = filePath.split('?')[0] @@ -292,7 +293,13 @@ export function extractStorageKey(filePath: string): string { } if (pathWithoutQuery.startsWith('/api/files/serve/')) { - return decodeURIComponent(pathWithoutQuery.substring('/api/files/serve/'.length)) + let key = decodeURIComponent(pathWithoutQuery.substring('/api/files/serve/'.length)) + if (key.startsWith('s3/')) { + key = key.substring(3) + } else if (key.startsWith('blob/')) { + key = key.substring(5) + } + return key } return pathWithoutQuery } diff --git a/apps/sim/proxy.ts b/apps/sim/proxy.ts index c117f04392..0d0c2cb647 100644 --- a/apps/sim/proxy.ts +++ b/apps/sim/proxy.ts @@ -144,7 +144,9 @@ export async function proxy(request: NextRequest) { if (hasActiveSession) { return NextResponse.redirect(new URL('/workspace', request.url)) } - return NextResponse.next() + const response = NextResponse.next() + response.headers.set('Content-Security-Policy', generateRuntimeCSP()) + return response } if (url.pathname.startsWith('/chat/')) { From 030ae5cc0a0c789a7b8f69b2beded5e31b7b3749 Mon Sep 17 00:00:00 2001 From: Adam Gough <77861281+aadamgough@users.noreply.github.com> Date: Thu, 11 Dec 2025 18:24:56 -0800 Subject: [PATCH 07/34] fix(tools): fixed tool outputs (#2325) * fix for asana and apify * fixed onedrive * fixed confluence error throwing and added upload file * fixed google vault tag dropdown and output * fix google group tag dropdown, var reference * fixed hubspot output * fixed pipedrive output * removed comments * removed more comments * consolidated file utils * fixed hubspot json schema * fix hubspot search tools * minor change --- apps/docs/content/docs/de/tools/apify.mdx | 1 - apps/docs/content/docs/en/tools/apify.mdx | 1 - apps/docs/content/docs/es/tools/apify.mdx | 1 - apps/docs/content/docs/fr/tools/apify.mdx | 1 - apps/docs/content/docs/ja/tools/apify.mdx | 1 - apps/docs/content/docs/zh/tools/apify.mdx | 1 - apps/sim/app/api/files/parse/route.ts | 49 +------ .../app/api/tools/asana/add-comment/route.ts | 22 ++- .../app/api/tools/asana/create-task/route.ts | 16 +-- .../app/api/tools/asana/get-projects/route.ts | 14 +- .../sim/app/api/tools/asana/get-task/route.ts | 102 +++++++------ .../app/api/tools/asana/search-tasks/route.ts | 54 ++++--- .../app/api/tools/asana/update-task/route.ts | 14 +- .../api/tools/confluence/create-page/route.ts | 32 ++++- .../confluence/upload-attachment/route.ts | 135 ++++++++++++++++++ .../app/api/tools/onedrive/upload/route.ts | 22 ++- .../components/icons/document-icons.tsx | 18 ++- .../components/tag-dropdown/tag-dropdown.tsx | 12 ++ apps/sim/blocks/blocks/asana.ts | 15 +- apps/sim/blocks/blocks/confluence.ts | 58 +++++++- apps/sim/blocks/blocks/google_groups.ts | 8 +- apps/sim/blocks/blocks/google_vault.ts | 13 +- apps/sim/blocks/blocks/hubspot.ts | 57 ++++++-- apps/sim/lib/uploads/utils/file-utils.ts | 69 +++++++++ apps/sim/tools/apify/run_actor_sync.ts | 1 - apps/sim/tools/asana/add_comment.ts | 30 ++-- apps/sim/tools/asana/create_task.ts | 36 ++--- apps/sim/tools/asana/get_projects.ts | 33 +++-- apps/sim/tools/asana/get_task.ts | 55 +++++-- apps/sim/tools/asana/search_tasks.ts | 52 +++++-- apps/sim/tools/asana/types.ts | 88 ++++++------ apps/sim/tools/asana/update_task.ts | 34 ++--- apps/sim/tools/confluence/index.ts | 2 + apps/sim/tools/confluence/types.ts | 23 +++ .../sim/tools/confluence/upload_attachment.ts | 134 +++++++++++++++++ apps/sim/tools/google_groups/add_member.ts | 6 +- apps/sim/tools/google_groups/create_group.ts | 6 +- apps/sim/tools/google_groups/delete_group.ts | 4 + apps/sim/tools/google_groups/get_group.ts | 6 +- apps/sim/tools/google_groups/get_member.ts | 6 +- apps/sim/tools/google_groups/has_member.ts | 6 +- apps/sim/tools/google_groups/list_groups.ts | 10 +- apps/sim/tools/google_groups/list_members.ts | 10 +- apps/sim/tools/google_groups/remove_member.ts | 4 + apps/sim/tools/google_groups/update_group.ts | 6 +- apps/sim/tools/google_groups/update_member.ts | 6 +- apps/sim/tools/google_vault/create_matters.ts | 6 +- .../google_vault/create_matters_export.ts | 6 +- .../google_vault/create_matters_holds.ts | 6 +- apps/sim/tools/google_vault/list_matters.ts | 13 +- .../tools/google_vault/list_matters_export.ts | 16 ++- .../tools/google_vault/list_matters_holds.ts | 13 +- apps/sim/tools/hubspot/create_company.ts | 28 ++-- apps/sim/tools/hubspot/create_contact.ts | 28 ++-- apps/sim/tools/hubspot/get_company.ts | 17 +-- apps/sim/tools/hubspot/get_contact.ts | 17 +-- apps/sim/tools/hubspot/get_users.ts | 17 +-- apps/sim/tools/hubspot/list_companies.ts | 22 +-- apps/sim/tools/hubspot/list_contacts.ts | 22 +-- apps/sim/tools/hubspot/list_deals.ts | 22 +-- apps/sim/tools/hubspot/search_companies.ts | 93 ++++++------ apps/sim/tools/hubspot/search_contacts.ts | 93 ++++++------ apps/sim/tools/hubspot/types.ts | 32 ++--- apps/sim/tools/hubspot/update_company.ts | 28 ++-- apps/sim/tools/hubspot/update_contact.ts | 28 ++-- apps/sim/tools/onedrive/upload.ts | 18 +-- apps/sim/tools/pipedrive/create_activity.ts | 17 +-- apps/sim/tools/pipedrive/create_deal.ts | 17 +-- apps/sim/tools/pipedrive/create_lead.ts | 17 +-- apps/sim/tools/pipedrive/create_project.ts | 17 +-- apps/sim/tools/pipedrive/delete_lead.ts | 17 +-- apps/sim/tools/pipedrive/get_activities.ts | 17 +-- apps/sim/tools/pipedrive/get_all_deals.ts | 40 +----- apps/sim/tools/pipedrive/get_deal.ts | 17 +-- apps/sim/tools/pipedrive/get_files.ts | 17 +-- apps/sim/tools/pipedrive/get_leads.ts | 22 +-- apps/sim/tools/pipedrive/get_mail_messages.ts | 17 +-- apps/sim/tools/pipedrive/get_mail_thread.ts | 17 +-- .../sim/tools/pipedrive/get_pipeline_deals.ts | 17 +-- apps/sim/tools/pipedrive/get_pipelines.ts | 17 +-- apps/sim/tools/pipedrive/get_projects.ts | 22 +-- apps/sim/tools/pipedrive/update_activity.ts | 17 +-- apps/sim/tools/pipedrive/update_deal.ts | 17 +-- apps/sim/tools/pipedrive/update_lead.ts | 17 +-- apps/sim/tools/registry.ts | 2 + 85 files changed, 1183 insertions(+), 957 deletions(-) create mode 100644 apps/sim/app/api/tools/confluence/upload-attachment/route.ts create mode 100644 apps/sim/tools/confluence/upload_attachment.ts diff --git a/apps/docs/content/docs/de/tools/apify.mdx b/apps/docs/content/docs/de/tools/apify.mdx index c8c82105c7..cb8385055c 100644 --- a/apps/docs/content/docs/de/tools/apify.mdx +++ b/apps/docs/content/docs/de/tools/apify.mdx @@ -54,7 +54,6 @@ Führe einen APIFY-Aktor synchron aus und erhalte Ergebnisse (maximal 5 Minuten) | `success` | boolean | Ob die Aktor-Ausführung erfolgreich war | | `runId` | string | APIFY-Ausführungs-ID | | `status` | string | Ausführungsstatus \(SUCCEEDED, FAILED, usw.\) | -| `datasetId` | string | Dataset-ID mit Ergebnissen | | `items` | array | Dataset-Elemente \(falls abgeschlossen\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/en/tools/apify.mdx b/apps/docs/content/docs/en/tools/apify.mdx index d26a1eb70a..2ba9276b1c 100644 --- a/apps/docs/content/docs/en/tools/apify.mdx +++ b/apps/docs/content/docs/en/tools/apify.mdx @@ -57,7 +57,6 @@ Run an APIFY actor synchronously and get results (max 5 minutes) | `success` | boolean | Whether the actor run succeeded | | `runId` | string | APIFY run ID | | `status` | string | Run status \(SUCCEEDED, FAILED, etc.\) | -| `datasetId` | string | Dataset ID containing results | | `items` | array | Dataset items \(if completed\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/es/tools/apify.mdx b/apps/docs/content/docs/es/tools/apify.mdx index 5a712eee12..0e925d41c4 100644 --- a/apps/docs/content/docs/es/tools/apify.mdx +++ b/apps/docs/content/docs/es/tools/apify.mdx @@ -54,7 +54,6 @@ Ejecuta un actor de APIFY de forma sincrónica y obtén resultados (máximo 5 mi | `success` | boolean | Si la ejecución del actor tuvo éxito | | `runId` | string | ID de ejecución de APIFY | | `status` | string | Estado de la ejecución \(SUCCEEDED, FAILED, etc.\) | -| `datasetId` | string | ID del conjunto de datos que contiene los resultados | | `items` | array | Elementos del conjunto de datos \(si se completó\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/fr/tools/apify.mdx b/apps/docs/content/docs/fr/tools/apify.mdx index 150c967ef7..8010f2cad3 100644 --- a/apps/docs/content/docs/fr/tools/apify.mdx +++ b/apps/docs/content/docs/fr/tools/apify.mdx @@ -54,7 +54,6 @@ Exécuter un acteur APIFY de manière synchrone et obtenir les résultats (maxim | `success` | booléen | Indique si l'exécution de l'acteur a réussi | | `runId` | chaîne | ID d'exécution APIFY | | `status` | chaîne | Statut d'exécution \(SUCCEEDED, FAILED, etc.\) | -| `datasetId` | chaîne | ID du jeu de données contenant les résultats | | `items` | tableau | Éléments du jeu de données \(si terminé\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/ja/tools/apify.mdx b/apps/docs/content/docs/ja/tools/apify.mdx index ff5ef18f65..04b4ae19d2 100644 --- a/apps/docs/content/docs/ja/tools/apify.mdx +++ b/apps/docs/content/docs/ja/tools/apify.mdx @@ -54,7 +54,6 @@ APIPYアクターを同期的に実行して結果を取得(最大5分) | `success` | boolean | アクター実行が成功したかどうか | | `runId` | string | APIFY実行ID | | `status` | string | 実行ステータス(SUCCEEDED、FAILEDなど) | -| `datasetId` | string | 結果を含むデータセットID | | `items` | array | データセット項目(完了した場合) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/zh/tools/apify.mdx b/apps/docs/content/docs/zh/tools/apify.mdx index c384c060b8..66dfb5b403 100644 --- a/apps/docs/content/docs/zh/tools/apify.mdx +++ b/apps/docs/content/docs/zh/tools/apify.mdx @@ -54,7 +54,6 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | `success` | boolean | actor 运行是否成功 | | `runId` | string | APIFY 运行 ID | | `status` | string | 运行状态 \(SUCCEEDED, FAILED 等\) | -| `datasetId` | string | 包含结果的数据集 ID | | `items` | array | 数据集条目 \(如果已完成\) | ### `apify_run_actor_async` diff --git a/apps/sim/app/api/files/parse/route.ts b/apps/sim/app/api/files/parse/route.ts index 62a5dd44c2..d02d077325 100644 --- a/apps/sim/app/api/files/parse/route.ts +++ b/apps/sim/app/api/files/parse/route.ts @@ -15,6 +15,7 @@ import { extractCleanFilename, extractStorageKey, extractWorkspaceIdFromExecutionKey, + getMimeTypeFromExtension, getViewerUrl, inferContextFromKey, } from '@/lib/uploads/utils/file-utils' @@ -44,36 +45,6 @@ interface ParseResult { } } -const fileTypeMap: Record = { - // Text formats - txt: 'text/plain', - csv: 'text/csv', - json: 'application/json', - xml: 'application/xml', - md: 'text/markdown', - html: 'text/html', - css: 'text/css', - js: 'application/javascript', - ts: 'application/typescript', - // Document formats - pdf: 'application/pdf', - doc: 'application/msword', - docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - // Spreadsheet formats - xls: 'application/vnd.ms-excel', - xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - // Presentation formats - ppt: 'application/vnd.ms-powerpoint', - pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - // Image formats - png: 'image/png', - jpg: 'image/jpeg', - jpeg: 'image/jpeg', - gif: 'image/gif', - // Archive formats - zip: 'application/zip', -} - /** * Main API route handler */ @@ -382,7 +353,8 @@ async function handleExternalUrl( }) } else { const { uploadWorkspaceFile } = await import('@/lib/uploads/contexts/workspace') - const mimeType = response.headers.get('content-type') || getMimeType(extension) + const mimeType = + response.headers.get('content-type') || getMimeTypeFromExtension(extension) await uploadWorkspaceFile(workspaceId, userId, buffer, filename, mimeType) logger.info(`Saved URL file to workspace storage: ${filename}`) } @@ -574,7 +546,7 @@ async function handleLocalFile( content: result.content, filePath, metadata: { - fileType: fileType || getMimeType(extension), + fileType: fileType || getMimeTypeFromExtension(extension), size: stats.size, hash, processingTime: 0, @@ -709,7 +681,7 @@ async function handleGenericTextBuffer( content: result.content, filePath: originalPath || filename, metadata: { - fileType: fileType || getMimeType(extension), + fileType: fileType || getMimeTypeFromExtension(extension), size: fileBuffer.length, hash: createHash('md5').update(fileBuffer).digest('hex'), processingTime: 0, @@ -727,7 +699,7 @@ async function handleGenericTextBuffer( content, filePath: originalPath || filename, metadata: { - fileType: fileType || getMimeType(extension), + fileType: fileType || getMimeTypeFromExtension(extension), size: fileBuffer.length, hash: createHash('md5').update(fileBuffer).digest('hex'), processingTime: 0, @@ -768,7 +740,7 @@ function handleGenericBuffer( content, filePath: filename, metadata: { - fileType: fileType || getMimeType(extension), + fileType: fileType || getMimeTypeFromExtension(extension), size: fileBuffer.length, hash: createHash('md5').update(fileBuffer).digest('hex'), processingTime: 0, @@ -791,13 +763,6 @@ async function parseBufferAsPdf(buffer: Buffer) { } } -/** - * Get MIME type from file extension - */ -function getMimeType(extension: string): string { - return fileTypeMap[extension] || 'application/octet-stream' -} - /** * Format bytes to human readable size */ diff --git a/apps/sim/app/api/tools/asana/add-comment/route.ts b/apps/sim/app/api/tools/asana/add-comment/route.ts index fa9bf681f2..bd00e151c0 100644 --- a/apps/sim/app/api/tools/asana/add-comment/route.ts +++ b/apps/sim/app/api/tools/asana/add-comment/route.ts @@ -86,18 +86,16 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - gid: story.gid, - text: story.text || '', - created_at: story.created_at, - created_by: story.created_by - ? { - gid: story.created_by.gid, - name: story.created_by.name, - } - : undefined, - }, + ts: new Date().toISOString(), + gid: story.gid, + text: story.text || '', + created_at: story.created_at, + created_by: story.created_by + ? { + gid: story.created_by.gid, + name: story.created_by.name, + } + : undefined, }) } catch (error) { logger.error('Error processing request:', error) diff --git a/apps/sim/app/api/tools/asana/create-task/route.ts b/apps/sim/app/api/tools/asana/create-task/route.ts index 70bd00f1b4..69200e6d90 100644 --- a/apps/sim/app/api/tools/asana/create-task/route.ts +++ b/apps/sim/app/api/tools/asana/create-task/route.ts @@ -99,15 +99,13 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - gid: task.gid, - name: task.name, - notes: task.notes || '', - completed: task.completed || false, - created_at: task.created_at, - permalink_url: task.permalink_url, - }, + ts: new Date().toISOString(), + gid: task.gid, + name: task.name, + notes: task.notes || '', + completed: task.completed || false, + created_at: task.created_at, + permalink_url: task.permalink_url, }) } catch (error: any) { logger.error('Error creating Asana task:', { diff --git a/apps/sim/app/api/tools/asana/get-projects/route.ts b/apps/sim/app/api/tools/asana/get-projects/route.ts index 5e93e93c4b..f26da3fd9a 100644 --- a/apps/sim/app/api/tools/asana/get-projects/route.ts +++ b/apps/sim/app/api/tools/asana/get-projects/route.ts @@ -73,14 +73,12 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - projects: projects.map((project: any) => ({ - gid: project.gid, - name: project.name, - resource_type: project.resource_type, - })), - }, + ts: new Date().toISOString(), + projects: projects.map((project: any) => ({ + gid: project.gid, + name: project.name, + resource_type: project.resource_type, + })), }) } catch (error) { logger.error('Error processing request:', error) diff --git a/apps/sim/app/api/tools/asana/get-task/route.ts b/apps/sim/app/api/tools/asana/get-task/route.ts index 8122986e9e..bcc459e4c5 100644 --- a/apps/sim/app/api/tools/asana/get-task/route.ts +++ b/apps/sim/app/api/tools/asana/get-task/route.ts @@ -69,31 +69,29 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - gid: task.gid, - resource_type: task.resource_type, - resource_subtype: task.resource_subtype, - name: task.name, - notes: task.notes || '', - completed: task.completed || false, - assignee: task.assignee - ? { - gid: task.assignee.gid, - name: task.assignee.name, - } - : undefined, - created_by: task.created_by - ? { - gid: task.created_by.gid, - resource_type: task.created_by.resource_type, - name: task.created_by.name, - } - : undefined, - due_on: task.due_on || undefined, - created_at: task.created_at, - modified_at: task.modified_at, - }, + ts: new Date().toISOString(), + gid: task.gid, + resource_type: task.resource_type, + resource_subtype: task.resource_subtype, + name: task.name, + notes: task.notes || '', + completed: task.completed || false, + assignee: task.assignee + ? { + gid: task.assignee.gid, + name: task.assignee.name, + } + : undefined, + created_by: task.created_by + ? { + gid: task.created_by.gid, + resource_type: task.created_by.resource_type, + name: task.created_by.name, + } + : undefined, + due_on: task.due_on || undefined, + created_at: task.created_at, + modified_at: task.modified_at, }) } @@ -180,34 +178,32 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - tasks: tasks.map((task: any) => ({ - gid: task.gid, - resource_type: task.resource_type, - resource_subtype: task.resource_subtype, - name: task.name, - notes: task.notes || '', - completed: task.completed || false, - assignee: task.assignee - ? { - gid: task.assignee.gid, - name: task.assignee.name, - } - : undefined, - created_by: task.created_by - ? { - gid: task.created_by.gid, - resource_type: task.created_by.resource_type, - name: task.created_by.name, - } - : undefined, - due_on: task.due_on || undefined, - created_at: task.created_at, - modified_at: task.modified_at, - })), - next_page: result.next_page, - }, + ts: new Date().toISOString(), + tasks: tasks.map((task: any) => ({ + gid: task.gid, + resource_type: task.resource_type, + resource_subtype: task.resource_subtype, + name: task.name, + notes: task.notes || '', + completed: task.completed || false, + assignee: task.assignee + ? { + gid: task.assignee.gid, + name: task.assignee.name, + } + : undefined, + created_by: task.created_by + ? { + gid: task.created_by.gid, + resource_type: task.created_by.resource_type, + name: task.created_by.name, + } + : undefined, + due_on: task.due_on || undefined, + created_at: task.created_at, + modified_at: task.modified_at, + })), + next_page: result.next_page, }) } catch (error) { logger.error('Error processing request:', error) diff --git a/apps/sim/app/api/tools/asana/search-tasks/route.ts b/apps/sim/app/api/tools/asana/search-tasks/route.ts index c6e7d8cb62..397b9b07ce 100644 --- a/apps/sim/app/api/tools/asana/search-tasks/route.ts +++ b/apps/sim/app/api/tools/asana/search-tasks/route.ts @@ -96,34 +96,32 @@ export async function POST(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - tasks: tasks.map((task: any) => ({ - gid: task.gid, - resource_type: task.resource_type, - resource_subtype: task.resource_subtype, - name: task.name, - notes: task.notes || '', - completed: task.completed || false, - assignee: task.assignee - ? { - gid: task.assignee.gid, - name: task.assignee.name, - } - : undefined, - created_by: task.created_by - ? { - gid: task.created_by.gid, - resource_type: task.created_by.resource_type, - name: task.created_by.name, - } - : undefined, - due_on: task.due_on || undefined, - created_at: task.created_at, - modified_at: task.modified_at, - })), - next_page: result.next_page, - }, + ts: new Date().toISOString(), + tasks: tasks.map((task: any) => ({ + gid: task.gid, + resource_type: task.resource_type, + resource_subtype: task.resource_subtype, + name: task.name, + notes: task.notes || '', + completed: task.completed || false, + assignee: task.assignee + ? { + gid: task.assignee.gid, + name: task.assignee.name, + } + : undefined, + created_by: task.created_by + ? { + gid: task.created_by.gid, + resource_type: task.created_by.resource_type, + name: task.created_by.name, + } + : undefined, + due_on: task.due_on || undefined, + created_at: task.created_at, + modified_at: task.modified_at, + })), + next_page: result.next_page, }) } catch (error) { logger.error('Error processing request:', error) diff --git a/apps/sim/app/api/tools/asana/update-task/route.ts b/apps/sim/app/api/tools/asana/update-task/route.ts index 2eca4d7c78..e83cc5ef9b 100644 --- a/apps/sim/app/api/tools/asana/update-task/route.ts +++ b/apps/sim/app/api/tools/asana/update-task/route.ts @@ -99,14 +99,12 @@ export async function PUT(request: Request) { return NextResponse.json({ success: true, - output: { - ts: new Date().toISOString(), - gid: task.gid, - name: task.name, - notes: task.notes || '', - completed: task.completed || false, - modified_at: task.modified_at, - }, + ts: new Date().toISOString(), + gid: task.gid, + name: task.name, + notes: task.notes || '', + completed: task.completed || false, + modified_at: task.modified_at, }) } catch (error: any) { logger.error('Error updating Asana task:', { diff --git a/apps/sim/app/api/tools/confluence/create-page/route.ts b/apps/sim/app/api/tools/confluence/create-page/route.ts index f049b86722..c50acf93e8 100644 --- a/apps/sim/app/api/tools/confluence/create-page/route.ts +++ b/apps/sim/app/api/tools/confluence/create-page/route.ts @@ -31,6 +31,16 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'Space ID is required' }, { status: 400 }) } + if (!/^\d+$/.test(String(spaceId))) { + return NextResponse.json( + { + error: + 'Invalid Space ID. The Space ID must be a numeric value, not the space key from the URL. Use the "list" operation to get all spaces with their numeric IDs.', + }, + { status: 400 } + ) + } + if (!title) { return NextResponse.json({ error: 'Title is required' }, { status: 400 }) } @@ -91,10 +101,24 @@ export async function POST(request: Request) { statusText: response.statusText, error: JSON.stringify(errorData, null, 2), }) - const errorMessage = - errorData?.message || - (errorData?.errors && JSON.stringify(errorData.errors)) || - `Failed to create Confluence page (${response.status})` + + let errorMessage = `Failed to create Confluence page (${response.status})` + if (errorData?.message) { + errorMessage = errorData.message + } else if (errorData?.errors && Array.isArray(errorData.errors)) { + const firstError = errorData.errors[0] + if (firstError?.title) { + if (firstError.title.includes("'spaceId'") && firstError.title.includes('Long')) { + errorMessage = + 'Invalid Space ID. Use the list spaces operation to find valid space IDs.' + } else { + errorMessage = firstError.title + } + } else { + errorMessage = JSON.stringify(errorData.errors) + } + } + return NextResponse.json({ error: errorMessage }, { status: response.status }) } diff --git a/apps/sim/app/api/tools/confluence/upload-attachment/route.ts b/apps/sim/app/api/tools/confluence/upload-attachment/route.ts new file mode 100644 index 0000000000..21e9f75ef8 --- /dev/null +++ b/apps/sim/app/api/tools/confluence/upload-attachment/route.ts @@ -0,0 +1,135 @@ +import { type NextRequest, NextResponse } from 'next/server' +import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation' +import { createLogger } from '@/lib/logs/console/logger' +import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils' +import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server' +import { getConfluenceCloudId } from '@/tools/confluence/utils' + +const logger = createLogger('ConfluenceUploadAttachmentAPI') + +export const dynamic = 'force-dynamic' + +export async function POST(request: NextRequest) { + try { + const body = await request.json() + const { domain, accessToken, cloudId: providedCloudId, pageId, file, fileName, comment } = body + + if (!domain) { + return NextResponse.json({ error: 'Domain is required' }, { status: 400 }) + } + + if (!accessToken) { + return NextResponse.json({ error: 'Access token is required' }, { status: 400 }) + } + + if (!pageId) { + return NextResponse.json({ error: 'Page ID is required' }, { status: 400 }) + } + + if (!file) { + return NextResponse.json({ error: 'File is required' }, { status: 400 }) + } + + const pageIdValidation = validateAlphanumericId(pageId, 'pageId', 255) + if (!pageIdValidation.isValid) { + return NextResponse.json({ error: pageIdValidation.error }, { status: 400 }) + } + + const cloudId = providedCloudId || (await getConfluenceCloudId(domain, accessToken)) + + const cloudIdValidation = validateJiraCloudId(cloudId, 'cloudId') + if (!cloudIdValidation.isValid) { + return NextResponse.json({ error: cloudIdValidation.error }, { status: 400 }) + } + + let fileToProcess = file + if (Array.isArray(file)) { + if (file.length === 0) { + return NextResponse.json({ error: 'No file provided' }, { status: 400 }) + } + fileToProcess = file[0] + } + + let userFile + try { + userFile = processSingleFileToUserFile(fileToProcess, 'confluence-upload', logger) + } catch (error) { + return NextResponse.json( + { error: error instanceof Error ? error.message : 'Failed to process file' }, + { status: 400 } + ) + } + + let fileBuffer: Buffer + try { + fileBuffer = await downloadFileFromStorage(userFile, 'confluence-upload', logger) + } catch (error) { + logger.error('Failed to download file from storage:', error) + return NextResponse.json( + { + error: `Failed to download file: ${error instanceof Error ? error.message : 'Unknown error'}`, + }, + { status: 500 } + ) + } + + const uploadFileName = fileName || userFile.name || 'attachment' + const mimeType = userFile.type || 'application/octet-stream' + + const url = `https://api.atlassian.com/ex/confluence/${cloudId}/wiki/rest/api/content/${pageId}/child/attachment` + + const formData = new FormData() + const blob = new Blob([new Uint8Array(fileBuffer)], { type: mimeType }) + formData.append('file', blob, uploadFileName) + + if (comment) { + formData.append('comment', comment) + } + + const response = await fetch(url, { + method: 'POST', + headers: { + Authorization: `Bearer ${accessToken}`, + 'X-Atlassian-Token': 'nocheck', + }, + body: formData, + }) + + if (!response.ok) { + const errorData = await response.json().catch(() => null) + logger.error('Confluence API error response:', { + status: response.status, + statusText: response.statusText, + error: JSON.stringify(errorData, null, 2), + }) + + let errorMessage = `Failed to upload attachment to Confluence (${response.status})` + if (errorData?.message) { + errorMessage = errorData.message + } else if (errorData?.errorMessage) { + errorMessage = errorData.errorMessage + } + + return NextResponse.json({ error: errorMessage }, { status: response.status }) + } + + const data = await response.json() + + const attachment = data.results?.[0] || data + + return NextResponse.json({ + attachmentId: attachment.id, + title: attachment.title, + fileSize: attachment.extensions?.fileSize || 0, + mediaType: attachment.extensions?.mediaType || mimeType, + downloadUrl: attachment._links?.download || '', + pageId: pageId, + }) + } catch (error) { + logger.error('Error uploading Confluence attachment:', error) + return NextResponse.json( + { error: (error as Error).message || 'Internal server error' }, + { status: 500 } + ) + } +} diff --git a/apps/sim/app/api/tools/onedrive/upload/route.ts b/apps/sim/app/api/tools/onedrive/upload/route.ts index 43875ce2a5..db79361204 100644 --- a/apps/sim/app/api/tools/onedrive/upload/route.ts +++ b/apps/sim/app/api/tools/onedrive/upload/route.ts @@ -4,7 +4,10 @@ import { z } from 'zod' import { checkHybridAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { createLogger } from '@/lib/logs/console/logger' -import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils' +import { + getExtensionFromMimeType, + processSingleFileToUserFile, +} from '@/lib/uploads/utils/file-utils' import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server' import { normalizeExcelValues } from '@/tools/onedrive/utils' @@ -27,9 +30,8 @@ const OneDriveUploadSchema = z.object({ fileName: z.string().min(1, 'File name is required'), file: z.any().optional(), // UserFile object (optional for blank Excel creation) folderId: z.string().optional().nullable(), - mimeType: z.string().optional(), - // Optional Excel write-after-create inputs - values: ExcelValuesSchema.optional(), + mimeType: z.string().nullish(), // Accept string, null, or undefined + values: ExcelValuesSchema.optional().nullable(), }) export async function POST(request: NextRequest) { @@ -149,9 +151,17 @@ export async function POST(request: NextRequest) { ) } - // Ensure file name has correct extension for Excel files + // Ensure file name has an appropriate extension let fileName = validatedData.fileName - if (isExcelCreation && !fileName.endsWith('.xlsx')) { + const hasExtension = fileName.includes('.') && fileName.lastIndexOf('.') > 0 + + if (!hasExtension) { + const extension = getExtensionFromMimeType(mimeType) + if (extension) { + fileName = `${fileName}.${extension}` + logger.info(`[${requestId}] Added extension to filename: ${fileName}`) + } + } else if (isExcelCreation && !fileName.endsWith('.xlsx')) { fileName = `${fileName.replace(/\.[^.]*$/, '')}.xlsx` } diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/icons/document-icons.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/icons/document-icons.tsx index 161dff2192..2eb04511a4 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/icons/document-icons.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/icons/document-icons.tsx @@ -1,4 +1,8 @@ import type React from 'react' +import { + SUPPORTED_AUDIO_EXTENSIONS, + SUPPORTED_VIDEO_EXTENSIONS, +} from '@/lib/uploads/utils/validation' interface IconProps { className?: string @@ -223,13 +227,19 @@ export const DefaultFileIcon: React.FC = ({ className = 'w-6 h-6' }) export function getDocumentIcon(mimeType: string, filename: string): React.FC { const extension = filename.split('.').pop()?.toLowerCase() - const audioExtensions = ['mp3', 'm4a', 'wav', 'webm', 'ogg', 'flac', 'aac', 'opus'] - if (mimeType.startsWith('audio/') || (extension && audioExtensions.includes(extension))) { + if ( + mimeType.startsWith('audio/') || + (extension && + SUPPORTED_AUDIO_EXTENSIONS.includes(extension as (typeof SUPPORTED_AUDIO_EXTENSIONS)[number])) + ) { return AudioIcon } - const videoExtensions = ['mp4', 'mov', 'avi', 'mkv'] - if (mimeType.startsWith('video/') || (extension && videoExtensions.includes(extension))) { + if ( + mimeType.startsWith('video/') || + (extension && + SUPPORTED_VIDEO_EXTENSIONS.includes(extension as (typeof SUPPORTED_VIDEO_EXTENSIONS)[number])) + ) { return VideoIcon } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx index ed1c16d2a8..e630e5bdc1 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx @@ -207,6 +207,18 @@ const generateOutputPaths = (outputs: Record, prefix = ''): string[ } else if (typeof value === 'object' && value !== null) { if ('type' in value && typeof value.type === 'string') { paths.push(currentPath) + if (value.type === 'object' && value.properties) { + paths.push(...generateOutputPaths(value.properties, currentPath)) + } else if (value.type === 'array' && value.items?.properties) { + paths.push(...generateOutputPaths(value.items.properties, currentPath)) + } else if ( + value.type === 'array' && + value.items && + typeof value.items === 'object' && + !('type' in value.items) + ) { + paths.push(...generateOutputPaths(value.items, currentPath)) + } } else { const subPaths = generateOutputPaths(value, currentPath) paths.push(...subPaths) diff --git a/apps/sim/blocks/blocks/asana.ts b/apps/sim/blocks/blocks/asana.ts index f4fa584f64..7f27e48862 100644 --- a/apps/sim/blocks/blocks/asana.ts +++ b/apps/sim/blocks/blocks/asana.ts @@ -287,6 +287,19 @@ export const AsanaBlock: BlockConfig = { }, outputs: { success: { type: 'boolean', description: 'Operation success status' }, - output: { type: 'string', description: 'Operation result (JSON)' }, + ts: { type: 'string', description: 'Timestamp of the response' }, + gid: { type: 'string', description: 'Resource globally unique identifier' }, + name: { type: 'string', description: 'Resource name' }, + notes: { type: 'string', description: 'Task notes or description' }, + completed: { type: 'boolean', description: 'Whether the task is completed' }, + text: { type: 'string', description: 'Comment text content' }, + assignee: { type: 'json', description: 'Assignee details (gid, name)' }, + created_by: { type: 'json', description: 'Creator details (gid, name)' }, + due_on: { type: 'string', description: 'Due date (YYYY-MM-DD)' }, + created_at: { type: 'string', description: 'Creation timestamp' }, + modified_at: { type: 'string', description: 'Last modified timestamp' }, + permalink_url: { type: 'string', description: 'URL to the resource in Asana' }, + tasks: { type: 'json', description: 'Array of tasks' }, + projects: { type: 'json', description: 'Array of projects' }, }, } diff --git a/apps/sim/blocks/blocks/confluence.ts b/apps/sim/blocks/blocks/confluence.ts index 67c10a0424..6823bb617a 100644 --- a/apps/sim/blocks/blocks/confluence.ts +++ b/apps/sim/blocks/blocks/confluence.ts @@ -29,6 +29,7 @@ export const ConfluenceBlock: BlockConfig = { { label: 'List Comments', id: 'list_comments' }, { label: 'Update Comment', id: 'update_comment' }, { label: 'Delete Comment', id: 'delete_comment' }, + { label: 'Upload Attachment', id: 'upload_attachment' }, { label: 'List Attachments', id: 'list_attachments' }, { label: 'Delete Attachment', id: 'delete_attachment' }, { label: 'List Labels', id: 'list_labels' }, @@ -155,6 +156,28 @@ export const ConfluenceBlock: BlockConfig = { required: true, condition: { field: 'operation', value: 'delete_attachment' }, }, + { + id: 'attachmentFile', + title: 'File', + type: 'file-upload', + placeholder: 'Select file to upload', + required: true, + condition: { field: 'operation', value: 'upload_attachment' }, + }, + { + id: 'attachmentFileName', + title: 'File Name', + type: 'short-input', + placeholder: 'Optional custom file name', + condition: { field: 'operation', value: 'upload_attachment' }, + }, + { + id: 'attachmentComment', + title: 'Comment', + type: 'short-input', + placeholder: 'Optional comment for the attachment', + condition: { field: 'operation', value: 'upload_attachment' }, + }, { id: 'labelName', title: 'Label Name', @@ -185,6 +208,7 @@ export const ConfluenceBlock: BlockConfig = { 'confluence_list_comments', 'confluence_update_comment', 'confluence_delete_comment', + 'confluence_upload_attachment', 'confluence_list_attachments', 'confluence_delete_attachment', 'confluence_list_labels', @@ -212,6 +236,8 @@ export const ConfluenceBlock: BlockConfig = { return 'confluence_update_comment' case 'delete_comment': return 'confluence_delete_comment' + case 'upload_attachment': + return 'confluence_upload_attachment' case 'list_attachments': return 'confluence_list_attachments' case 'delete_attachment': @@ -227,11 +253,19 @@ export const ConfluenceBlock: BlockConfig = { } }, params: (params) => { - const { credential, pageId, manualPageId, operation, ...rest } = params + const { + credential, + pageId, + manualPageId, + operation, + attachmentFile, + attachmentFileName, + attachmentComment, + ...rest + } = params const effectivePageId = (pageId || manualPageId || '').trim() - // Operations that require pageId const requiresPageId = [ 'read', 'update', @@ -240,9 +274,9 @@ export const ConfluenceBlock: BlockConfig = { 'list_comments', 'list_attachments', 'list_labels', + 'upload_attachment', ] - // Operations that require spaceId const requiresSpaceId = ['create', 'get_space'] if (requiresPageId.includes(operation) && !effectivePageId) { @@ -253,6 +287,18 @@ export const ConfluenceBlock: BlockConfig = { throw new Error('Space ID is required for this operation.') } + if (operation === 'upload_attachment') { + return { + credential, + pageId: effectivePageId, + operation, + file: attachmentFile, + fileName: attachmentFileName, + comment: attachmentComment, + ...rest, + } + } + return { credential, pageId: effectivePageId || undefined, @@ -276,6 +322,9 @@ export const ConfluenceBlock: BlockConfig = { comment: { type: 'string', description: 'Comment text' }, commentId: { type: 'string', description: 'Comment identifier' }, attachmentId: { type: 'string', description: 'Attachment identifier' }, + attachmentFile: { type: 'json', description: 'File to upload as attachment' }, + attachmentFileName: { type: 'string', description: 'Custom file name for attachment' }, + attachmentComment: { type: 'string', description: 'Comment for the attachment' }, labelName: { type: 'string', description: 'Label name' }, limit: { type: 'number', description: 'Maximum number of results' }, }, @@ -297,6 +346,9 @@ export const ConfluenceBlock: BlockConfig = { spaces: { type: 'array', description: 'List of spaces' }, commentId: { type: 'string', description: 'Comment identifier' }, attachmentId: { type: 'string', description: 'Attachment identifier' }, + fileSize: { type: 'number', description: 'Attachment file size in bytes' }, + mediaType: { type: 'string', description: 'Attachment MIME type' }, + downloadUrl: { type: 'string', description: 'Attachment download URL' }, labelName: { type: 'string', description: 'Label name' }, spaceId: { type: 'string', description: 'Space identifier' }, name: { type: 'string', description: 'Space name' }, diff --git a/apps/sim/blocks/blocks/google_groups.ts b/apps/sim/blocks/blocks/google_groups.ts index 658d66be74..99c3b5672b 100644 --- a/apps/sim/blocks/blocks/google_groups.ts +++ b/apps/sim/blocks/blocks/google_groups.ts @@ -312,6 +312,12 @@ export const GoogleGroupsBlock: BlockConfig = { roles: { type: 'string', description: 'Filter by roles for list members' }, }, outputs: { - output: { type: 'json', description: 'Google Groups API response data' }, + groups: { type: 'json', description: 'Array of group objects (for list_groups)' }, + group: { type: 'json', description: 'Single group object (for get/create/update_group)' }, + members: { type: 'json', description: 'Array of member objects (for list_members)' }, + member: { type: 'json', description: 'Single member object (for get/add/update_member)' }, + isMember: { type: 'boolean', description: 'Membership check result (for has_member)' }, + message: { type: 'string', description: 'Success message (for delete/remove operations)' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, }, } diff --git a/apps/sim/blocks/blocks/google_vault.ts b/apps/sim/blocks/blocks/google_vault.ts index 5f3513e053..92806faf99 100644 --- a/apps/sim/blocks/blocks/google_vault.ts +++ b/apps/sim/blocks/blocks/google_vault.ts @@ -257,9 +257,16 @@ export const GoogleVaultBlock: BlockConfig = { description: { type: 'string', description: 'Matter description' }, }, outputs: { - // Common outputs - output: { type: 'json', description: 'Vault API response data' }, - // Download export file output + matters: { type: 'json', description: 'Array of matter objects (for list_matters)' }, + exports: { type: 'json', description: 'Array of export objects (for list_matters_export)' }, + holds: { type: 'json', description: 'Array of hold objects (for list_matters_holds)' }, + matter: { type: 'json', description: 'Created matter object (for create_matters)' }, + export: { type: 'json', description: 'Created export object (for create_matters_export)' }, + hold: { type: 'json', description: 'Created hold object (for create_matters_holds)' }, file: { type: 'json', description: 'Downloaded export file (UserFile) from execution files' }, + nextPageToken: { + type: 'string', + description: 'Token for fetching next page of results (for list operations)', + }, }, } diff --git a/apps/sim/blocks/blocks/hubspot.ts b/apps/sim/blocks/blocks/hubspot.ts index 218284bca1..fcd3e6d65b 100644 --- a/apps/sim/blocks/blocks/hubspot.ts +++ b/apps/sim/blocks/blocks/hubspot.ts @@ -72,21 +72,37 @@ export const HubSpotBlock: BlockConfig = { id: 'contactId', title: 'Contact ID or Email', type: 'short-input', - placeholder: 'Optional - Leave empty to list all contacts', - condition: { field: 'operation', value: ['get_contacts', 'update_contact'] }, + placeholder: 'Leave empty to list all contacts', + condition: { field: 'operation', value: 'get_contacts' }, + }, + { + id: 'contactId', + title: 'Contact ID or Email', + type: 'short-input', + placeholder: 'Numeric ID, or email (requires ID Property below)', + condition: { field: 'operation', value: 'update_contact' }, + required: true, }, { id: 'companyId', title: 'Company ID or Domain', type: 'short-input', - placeholder: 'Optional - Leave empty to list all companies', - condition: { field: 'operation', value: ['get_companies', 'update_company'] }, + placeholder: 'Leave empty to list all companies', + condition: { field: 'operation', value: 'get_companies' }, + }, + { + id: 'companyId', + title: 'Company ID or Domain', + type: 'short-input', + placeholder: 'Numeric ID, or domain (requires ID Property below)', + condition: { field: 'operation', value: 'update_company' }, + required: true, }, { id: 'idProperty', title: 'ID Property', type: 'short-input', - placeholder: 'Optional - e.g., "email" for contacts, "domain" for companies', + placeholder: 'Required if using email/domain (e.g., "email" or "domain")', condition: { field: 'operation', value: ['get_contacts', 'update_contact', 'get_companies', 'update_company'], @@ -822,33 +838,48 @@ Return ONLY the JSON array of property names - no explanations, no markdown, no credential, } - if (propertiesToSet) { + const createUpdateOps = [ + 'create_contact', + 'update_contact', + 'create_company', + 'update_company', + ] + if (propertiesToSet && createUpdateOps.includes(operation as string)) { cleanParams.properties = propertiesToSet } - if (properties && !searchProperties) { + const getListOps = ['get_contacts', 'get_companies', 'get_deals'] + if (properties && !searchProperties && getListOps.includes(operation as string)) { cleanParams.properties = properties } - if (searchProperties) { + const searchOps = ['search_contacts', 'search_companies'] + if (searchProperties && searchOps.includes(operation as string)) { cleanParams.properties = searchProperties } - if (filterGroups) { + if (filterGroups && searchOps.includes(operation as string)) { cleanParams.filterGroups = filterGroups } - if (sorts) { + if (sorts && searchOps.includes(operation as string)) { cleanParams.sorts = sorts } - if (associations) { + if (associations && ['create_contact', 'create_company'].includes(operation as string)) { cleanParams.associations = associations } - // Add other params + const excludeKeys = [ + 'propertiesToSet', + 'properties', + 'searchProperties', + 'filterGroups', + 'sorts', + 'associations', + ] Object.entries(rest).forEach(([key, value]) => { - if (value !== undefined && value !== null && value !== '') { + if (value !== undefined && value !== null && value !== '' && !excludeKeys.includes(key)) { cleanParams[key] = value } }) diff --git a/apps/sim/lib/uploads/utils/file-utils.ts b/apps/sim/lib/uploads/utils/file-utils.ts index 4a1876f1a7..69042f7ef2 100644 --- a/apps/sim/lib/uploads/utils/file-utils.ts +++ b/apps/sim/lib/uploads/utils/file-utils.ts @@ -214,6 +214,75 @@ export function getMimeTypeFromExtension(extension: string): string { return extensionMimeMap[extension.toLowerCase()] || 'application/octet-stream' } +/** + * Get file extension from MIME type + * @param mimeType - MIME type string + * @returns File extension without dot, or null if not found + */ +export function getExtensionFromMimeType(mimeType: string): string | null { + const mimeToExtension: Record = { + // Images + 'image/jpeg': 'jpg', + 'image/jpg': 'jpg', + 'image/png': 'png', + 'image/gif': 'gif', + 'image/webp': 'webp', + 'image/svg+xml': 'svg', + + // Documents + 'application/pdf': 'pdf', + 'text/plain': 'txt', + 'text/csv': 'csv', + 'application/json': 'json', + 'application/xml': 'xml', + 'text/xml': 'xml', + 'text/html': 'html', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx', + 'application/msword': 'doc', + 'application/vnd.ms-excel': 'xls', + 'application/vnd.ms-powerpoint': 'ppt', + 'text/markdown': 'md', + 'application/rtf': 'rtf', + + // Audio + 'audio/mpeg': 'mp3', + 'audio/mp3': 'mp3', + 'audio/mp4': 'm4a', + 'audio/x-m4a': 'm4a', + 'audio/m4a': 'm4a', + 'audio/wav': 'wav', + 'audio/wave': 'wav', + 'audio/x-wav': 'wav', + 'audio/webm': 'webm', + 'audio/ogg': 'ogg', + 'audio/vorbis': 'ogg', + 'audio/flac': 'flac', + 'audio/x-flac': 'flac', + 'audio/aac': 'aac', + 'audio/x-aac': 'aac', + 'audio/opus': 'opus', + + // Video + 'video/mp4': 'mp4', + 'video/mpeg': 'mpg', + 'video/quicktime': 'mov', + 'video/x-quicktime': 'mov', + 'video/x-msvideo': 'avi', + 'video/avi': 'avi', + 'video/x-matroska': 'mkv', + 'video/webm': 'webm', + + // Archives + 'application/zip': 'zip', + 'application/x-zip-compressed': 'zip', + 'application/gzip': 'gz', + } + + return mimeToExtension[mimeType.toLowerCase()] || null +} + /** * Format bytes to human-readable file size * @param bytes - File size in bytes diff --git a/apps/sim/tools/apify/run_actor_sync.ts b/apps/sim/tools/apify/run_actor_sync.ts index 8ef5533a04..f7991cfd0f 100644 --- a/apps/sim/tools/apify/run_actor_sync.ts +++ b/apps/sim/tools/apify/run_actor_sync.ts @@ -101,7 +101,6 @@ export const apifyRunActorSyncTool: ToolConfig = success: { type: 'boolean', description: 'Whether the actor run succeeded' }, runId: { type: 'string', description: 'APIFY run ID' }, status: { type: 'string', description: 'Run status (SUCCEEDED, FAILED, etc.)' }, - datasetId: { type: 'string', description: 'Dataset ID containing results' }, items: { type: 'array', description: 'Dataset items (if completed)' }, }, } diff --git a/apps/sim/tools/asana/add_comment.ts b/apps/sim/tools/asana/add_comment.ts index 0c2b67468f..413b1d2859 100644 --- a/apps/sim/tools/asana/add_comment.ts +++ b/apps/sim/tools/asana/add_comment.ts @@ -52,31 +52,33 @@ export const asanaAddCommentTool: ToolConfig - next_page?: { - offset: string - path: string - uri: string - } + created_by?: { + gid: string + resource_type: string + name: string } + due_on?: string + created_at: string + modified_at: string + }> + next_page?: { + offset: string + path: string + uri: string + } + } } export interface AsanaCreateTaskParams { diff --git a/apps/sim/tools/asana/update_task.ts b/apps/sim/tools/asana/update_task.ts index 6aa7aaa993..a015667063 100644 --- a/apps/sim/tools/asana/update_task.ts +++ b/apps/sim/tools/asana/update_task.ts @@ -92,33 +92,21 @@ export const asanaUpdateTaskTool: ToolConfig = { + id: 'confluence_upload_attachment', + name: 'Confluence Upload Attachment', + description: 'Upload a file as an attachment to a Confluence page.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'confluence', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'OAuth access token for Confluence', + }, + domain: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Confluence domain (e.g., yourcompany.atlassian.net)', + }, + pageId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Confluence page ID to attach the file to', + }, + file: { + type: 'file', + required: true, + visibility: 'user-or-llm', + description: 'The file to upload as an attachment', + }, + fileName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional custom file name for the attachment', + }, + comment: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional comment to add to the attachment', + }, + cloudId: { + type: 'string', + required: false, + visibility: 'user-only', + description: + 'Confluence Cloud ID for the instance. If not provided, it will be fetched using the domain.', + }, + }, + + request: { + url: () => '/api/tools/confluence/upload-attachment', + method: 'POST', + headers: (params: ConfluenceUploadAttachmentParams) => { + return { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: `Bearer ${params.accessToken}`, + } + }, + body: (params: ConfluenceUploadAttachmentParams) => { + return { + domain: params.domain, + accessToken: params.accessToken, + cloudId: params.cloudId, + pageId: params.pageId, + file: params.file, + fileName: params.fileName, + comment: params.comment, + } + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + return { + success: true, + output: { + ts: new Date().toISOString(), + attachmentId: data.attachmentId || '', + title: data.title || '', + fileSize: data.fileSize || 0, + mediaType: data.mediaType || '', + downloadUrl: data.downloadUrl || '', + pageId: data.pageId || '', + }, + } + }, + + outputs: { + ts: { type: 'string', description: 'Timestamp of upload' }, + attachmentId: { type: 'string', description: 'Uploaded attachment ID' }, + title: { type: 'string', description: 'Attachment file name' }, + fileSize: { type: 'number', description: 'File size in bytes' }, + mediaType: { type: 'string', description: 'MIME type of the attachment' }, + downloadUrl: { type: 'string', description: 'Download URL for the attachment' }, + pageId: { type: 'string', description: 'Page ID the attachment was added to' }, + }, +} diff --git a/apps/sim/tools/google_groups/add_member.ts b/apps/sim/tools/google_groups/add_member.ts index 0a306efb61..e2d1e967e6 100644 --- a/apps/sim/tools/google_groups/add_member.ts +++ b/apps/sim/tools/google_groups/add_member.ts @@ -66,7 +66,11 @@ export const addMemberTool: ToolConfig = { if (!response.ok) { throw new Error(data.error?.message || 'Failed to create matter') } - return { success: true, output: data } + return { success: true, output: { matter: data } } + }, + + outputs: { + matter: { type: 'json', description: 'Created matter object' }, }, } diff --git a/apps/sim/tools/google_vault/create_matters_export.ts b/apps/sim/tools/google_vault/create_matters_export.ts index a65a31232a..f468fc7ab7 100644 --- a/apps/sim/tools/google_vault/create_matters_export.ts +++ b/apps/sim/tools/google_vault/create_matters_export.ts @@ -91,6 +91,10 @@ export const createMattersExportTool: ToolConfig = { return `https://vault.googleapis.com/v1/matters/${params.matterId}` } const url = new URL('https://vault.googleapis.com/v1/matters') - // Handle pageSize - convert to number if needed if (params.pageSize !== undefined && params.pageSize !== null) { const pageSize = Number(params.pageSize) if (Number.isFinite(pageSize) && pageSize > 0) { @@ -39,18 +38,26 @@ export const listMattersTool: ToolConfig = { } } if (params.pageToken) url.searchParams.set('pageToken', params.pageToken) - // Default BASIC view implicitly by omitting 'view' and 'state' params return url.toString() }, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }), }, - transformResponse: async (response: Response) => { + transformResponse: async (response: Response, params?: GoogleVaultListMattersParams) => { const data = await response.json() if (!response.ok) { throw new Error(data.error?.message || 'Failed to list matters') } + if (params?.matterId) { + return { success: true, output: { matter: data } } + } return { success: true, output: data } }, + + outputs: { + matters: { type: 'json', description: 'Array of matter objects' }, + matter: { type: 'json', description: 'Single matter object (when matterId is provided)' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + }, } diff --git a/apps/sim/tools/google_vault/list_matters_export.ts b/apps/sim/tools/google_vault/list_matters_export.ts index 3be55c01ab..539ccd11d2 100644 --- a/apps/sim/tools/google_vault/list_matters_export.ts +++ b/apps/sim/tools/google_vault/list_matters_export.ts @@ -1,8 +1,6 @@ import type { GoogleVaultListMattersExportParams } from '@/tools/google_vault/types' import type { ToolConfig } from '@/tools/types' -// matters.exports.list -// GET https://vault.googleapis.com/v1/matters/{matterId}/exports export const listMattersExportTool: ToolConfig = { id: 'list_matters_export', name: 'Vault List Exports (by Matter)', @@ -28,7 +26,6 @@ export const listMattersExportTool: ToolConfig 0) { @@ -42,13 +39,20 @@ export const listMattersExportTool: ToolConfig ({ Authorization: `Bearer ${params.accessToken}` }), }, - transformResponse: async (response: Response) => { + transformResponse: async (response: Response, params?: GoogleVaultListMattersExportParams) => { const data = await response.json() if (!response.ok) { throw new Error(data.error?.message || 'Failed to list exports') } - - // Return the raw API response without modifications + if (params?.exportId) { + return { success: true, output: { export: data } } + } return { success: true, output: data } }, + + outputs: { + exports: { type: 'json', description: 'Array of export objects' }, + export: { type: 'json', description: 'Single export object (when exportId is provided)' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + }, } diff --git a/apps/sim/tools/google_vault/list_matters_holds.ts b/apps/sim/tools/google_vault/list_matters_holds.ts index 0e8e35f017..6f7a90cdce 100644 --- a/apps/sim/tools/google_vault/list_matters_holds.ts +++ b/apps/sim/tools/google_vault/list_matters_holds.ts @@ -26,7 +26,6 @@ export const listMattersHoldsTool: ToolConfig return `https://vault.googleapis.com/v1/matters/${params.matterId}/holds/${params.holdId}` } const url = new URL(`https://vault.googleapis.com/v1/matters/${params.matterId}/holds`) - // Handle pageSize - convert to number if needed if (params.pageSize !== undefined && params.pageSize !== null) { const pageSize = Number(params.pageSize) if (Number.isFinite(pageSize) && pageSize > 0) { @@ -34,18 +33,26 @@ export const listMattersHoldsTool: ToolConfig } } if (params.pageToken) url.searchParams.set('pageToken', params.pageToken) - // Default BASIC_HOLD implicitly by omitting 'view' return url.toString() }, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}` }), }, - transformResponse: async (response: Response) => { + transformResponse: async (response: Response, params?: GoogleVaultListMattersHoldsParams) => { const data = await response.json() if (!response.ok) { throw new Error(data.error?.message || 'Failed to list holds') } + if (params?.holdId) { + return { success: true, output: { hold: data } } + } return { success: true, output: data } }, + + outputs: { + holds: { type: 'json', description: 'Array of hold objects' }, + hold: { type: 'json', description: 'Single hold object (when holdId is provided)' }, + nextPageToken: { type: 'string', description: 'Token for fetching next page of results' }, + }, } diff --git a/apps/sim/tools/hubspot/create_company.ts b/apps/sim/tools/hubspot/create_company.ts index 589fc59989..9ead3fb5d8 100644 --- a/apps/sim/tools/hubspot/create_company.ts +++ b/apps/sim/tools/hubspot/create_company.ts @@ -56,8 +56,17 @@ export const hubspotCreateCompanyTool: ToolConfig< } }, body: (params) => { + let properties = params.properties + if (typeof properties === 'string') { + try { + properties = JSON.parse(properties) + } catch (e) { + throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.') + } + } + const body: any = { - properties: params.properties, + properties, } if (params.associations && params.associations.length > 0) { @@ -90,21 +99,8 @@ export const hubspotCreateCompanyTool: ToolConfig< }, outputs: { + company: { type: 'object', description: 'Created HubSpot company object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created company data', - properties: { - company: { - type: 'object', - description: 'Created company object with properties and ID', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/hubspot/create_contact.ts b/apps/sim/tools/hubspot/create_contact.ts index 1acc4f3452..11ec2894c3 100644 --- a/apps/sim/tools/hubspot/create_contact.ts +++ b/apps/sim/tools/hubspot/create_contact.ts @@ -59,8 +59,17 @@ export const hubspotCreateContactTool: ToolConfig< } }, body: (params) => { + let properties = params.properties + if (typeof properties === 'string') { + try { + properties = JSON.parse(properties) + } catch (e) { + throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.') + } + } + const body: any = { - properties: params.properties, + properties, } if (params.associations && params.associations.length > 0) { @@ -93,21 +102,8 @@ export const hubspotCreateContactTool: ToolConfig< }, outputs: { + contact: { type: 'object', description: 'Created HubSpot contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created contact data', - properties: { - contact: { - type: 'object', - description: 'Created contact object with properties and ID', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/hubspot/get_company.ts b/apps/sim/tools/hubspot/get_company.ts index 3ace7b1c3b..b8b684703a 100644 --- a/apps/sim/tools/hubspot/get_company.ts +++ b/apps/sim/tools/hubspot/get_company.ts @@ -103,21 +103,8 @@ export const hubspotGetCompanyTool: ToolConfig { const body: any = {} - if (params.filterGroups && params.filterGroups.length > 0) { - body.filterGroups = params.filterGroups + if (params.filterGroups) { + let parsedFilterGroups = params.filterGroups + if (typeof params.filterGroups === 'string') { + try { + parsedFilterGroups = JSON.parse(params.filterGroups) + } catch (e) { + throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) { + body.filterGroups = parsedFilterGroups + } } - if (params.sorts && params.sorts.length > 0) { - body.sorts = params.sorts + if (params.sorts) { + let parsedSorts = params.sorts + if (typeof params.sorts === 'string') { + try { + parsedSorts = JSON.parse(params.sorts) + } catch (e) { + throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedSorts) && parsedSorts.length > 0) { + body.sorts = parsedSorts + } } if (params.query) { body.query = params.query } - if (params.properties && params.properties.length > 0) { - body.properties = params.properties + if (params.properties) { + let parsedProperties = params.properties + if (typeof params.properties === 'string') { + try { + parsedProperties = JSON.parse(params.properties) + } catch (e) { + throw new Error(`Invalid JSON for properties: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedProperties) && parsedProperties.length > 0) { + body.properties = parsedProperties + } } if (params.limit) { body.limit = params.limit @@ -115,46 +145,29 @@ export const hubspotSearchCompaniesTool: ToolConfig< throw new Error(data.message || 'Failed to search companies in HubSpot') } - return { - success: true, - output: { - companies: data.results || [], + const result = { + companies: data.results || [], + total: data.total, + paging: data.paging, + metadata: { + operation: 'search_companies' as const, + totalReturned: data.results?.length || 0, total: data.total, - paging: data.paging, - metadata: { - operation: 'search_companies' as const, - totalReturned: data.results?.length || 0, - total: data.total, - }, - success: true, }, } + + return { + success: true, + output: result, + ...result, + } }, outputs: { + companies: { type: 'array', description: 'Array of matching HubSpot company objects' }, + total: { type: 'number', description: 'Total number of matching companies' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Search results', - properties: { - companies: { - type: 'array', - description: 'Array of matching company objects', - }, - total: { - type: 'number', - description: 'Total number of matching companies', - }, - paging: { - type: 'object', - description: 'Pagination information', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/hubspot/search_contacts.ts b/apps/sim/tools/hubspot/search_contacts.ts index 4bed79b0d2..710b279337 100644 --- a/apps/sim/tools/hubspot/search_contacts.ts +++ b/apps/sim/tools/hubspot/search_contacts.ts @@ -84,17 +84,47 @@ export const hubspotSearchContactsTool: ToolConfig< body: (params) => { const body: any = {} - if (params.filterGroups && params.filterGroups.length > 0) { - body.filterGroups = params.filterGroups + if (params.filterGroups) { + let parsedFilterGroups = params.filterGroups + if (typeof params.filterGroups === 'string') { + try { + parsedFilterGroups = JSON.parse(params.filterGroups) + } catch (e) { + throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) { + body.filterGroups = parsedFilterGroups + } } - if (params.sorts && params.sorts.length > 0) { - body.sorts = params.sorts + if (params.sorts) { + let parsedSorts = params.sorts + if (typeof params.sorts === 'string') { + try { + parsedSorts = JSON.parse(params.sorts) + } catch (e) { + throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedSorts) && parsedSorts.length > 0) { + body.sorts = parsedSorts + } } if (params.query) { body.query = params.query } - if (params.properties && params.properties.length > 0) { - body.properties = params.properties + if (params.properties) { + let parsedProperties = params.properties + if (typeof params.properties === 'string') { + try { + parsedProperties = JSON.parse(params.properties) + } catch (e) { + throw new Error(`Invalid JSON for properties: ${(e as Error).message}`) + } + } + if (Array.isArray(parsedProperties) && parsedProperties.length > 0) { + body.properties = parsedProperties + } } if (params.limit) { body.limit = params.limit @@ -115,46 +145,29 @@ export const hubspotSearchContactsTool: ToolConfig< throw new Error(data.message || 'Failed to search contacts in HubSpot') } - return { - success: true, - output: { - contacts: data.results || [], + const result = { + contacts: data.results || [], + total: data.total, + paging: data.paging, + metadata: { + operation: 'search_contacts' as const, + totalReturned: data.results?.length || 0, total: data.total, - paging: data.paging, - metadata: { - operation: 'search_contacts' as const, - totalReturned: data.results?.length || 0, - total: data.total, - }, - success: true, }, } + + return { + success: true, + output: result, + ...result, + } }, outputs: { + contacts: { type: 'array', description: 'Array of matching HubSpot contact objects' }, + total: { type: 'number', description: 'Total number of matching contacts' }, + paging: { type: 'object', description: 'Pagination information' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Search results', - properties: { - contacts: { - type: 'array', - description: 'Array of matching contact objects', - }, - total: { - type: 'number', - description: 'Total number of matching contacts', - }, - paging: { - type: 'object', - description: 'Pagination information', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/hubspot/types.ts b/apps/sim/tools/hubspot/types.ts index 920d6d2a62..23e3084997 100644 --- a/apps/sim/tools/hubspot/types.ts +++ b/apps/sim/tools/hubspot/types.ts @@ -131,16 +131,13 @@ export interface HubSpotUpdateContactParams { // Search Contacts export interface HubSpotSearchContactsResponse extends ToolResponse { - output: { - contacts: HubSpotContact[] + contacts: HubSpotContact[] + total: number + paging?: HubSpotPaging + metadata: { + operation: 'search_contacts' + totalReturned: number total: number - paging?: HubSpotPaging - metadata: { - operation: 'search_contacts' - totalReturned: number - total: number - } - success: boolean } } @@ -212,17 +209,14 @@ export type HubSpotUpdateCompanyResponse = Omit & { - output: { - companies: HubSpotContact[] +export interface HubSpotSearchCompaniesResponse extends ToolResponse { + companies: HubSpotContact[] + total: number + paging?: HubSpotPaging + metadata: { + operation: 'search_companies' + totalReturned: number total: number - paging?: HubSpotPaging - metadata: { - operation: 'search_companies' - totalReturned: number - total: number - } - success: boolean } } diff --git a/apps/sim/tools/hubspot/update_company.ts b/apps/sim/tools/hubspot/update_company.ts index cf8c9ce8f1..2812a39e4d 100644 --- a/apps/sim/tools/hubspot/update_company.ts +++ b/apps/sim/tools/hubspot/update_company.ts @@ -69,8 +69,17 @@ export const hubspotUpdateCompanyTool: ToolConfig< } }, body: (params) => { + let properties = params.properties + if (typeof properties === 'string') { + try { + properties = JSON.parse(properties) + } catch (e) { + throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.') + } + } + return { - properties: params.properties, + properties, } }, }, @@ -97,21 +106,8 @@ export const hubspotUpdateCompanyTool: ToolConfig< }, outputs: { + company: { type: 'object', description: 'Updated HubSpot company object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Updated company data', - properties: { - company: { - type: 'object', - description: 'Updated company object with properties', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/hubspot/update_contact.ts b/apps/sim/tools/hubspot/update_contact.ts index 755a192576..59fbae4f5e 100644 --- a/apps/sim/tools/hubspot/update_contact.ts +++ b/apps/sim/tools/hubspot/update_contact.ts @@ -69,8 +69,17 @@ export const hubspotUpdateContactTool: ToolConfig< } }, body: (params) => { + let properties = params.properties + if (typeof properties === 'string') { + try { + properties = JSON.parse(properties) + } catch (e) { + throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.') + } + } + return { - properties: params.properties, + properties, } }, }, @@ -97,21 +106,8 @@ export const hubspotUpdateContactTool: ToolConfig< }, outputs: { + contact: { type: 'object', description: 'Updated HubSpot contact object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Updated contact data', - properties: { - contact: { - type: 'object', - description: 'Updated contact object with properties', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/onedrive/upload.ts b/apps/sim/tools/onedrive/upload.ts index 6d4cc366a7..b523613f78 100644 --- a/apps/sim/tools/onedrive/upload.ts +++ b/apps/sim/tools/onedrive/upload.ts @@ -63,32 +63,25 @@ export const uploadTool: ToolConfig request: { url: (params) => { - // If file is provided OR Excel file is being created, use custom API route const isExcelFile = params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' if (params.file || isExcelFile) { return '/api/tools/onedrive/upload' } - // Direct upload for text files - use Microsoft Graph API let fileName = params.fileName || 'untitled' - // For text files, ensure .txt extension if (!fileName.endsWith('.txt')) { - // Remove any existing extensions and add .txt fileName = `${fileName.replace(/\.[^.]*$/, '')}.txt` } - // Build the proper URL based on parent folder const parentFolderId = params.manualFolderId || params.folderSelector if (parentFolderId && parentFolderId.trim() !== '') { return `https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(parentFolderId)}:/${fileName}:/content` } - // Default to root folder return `https://graph.microsoft.com/v1.0/me/drive/root:/${fileName}:/content` }, method: (params) => { - // Use POST for custom API route (file uploads or Excel creation), PUT for direct text upload const isExcelFile = params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' return params.file || isExcelFile ? 'POST' : 'PUT' @@ -98,11 +91,9 @@ export const uploadTool: ToolConfig const isExcelFile = params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - // For file uploads or Excel creation via custom API, send JSON if (params.file || isExcelFile) { headers['Content-Type'] = 'application/json' } else { - // For direct text uploads, use direct PUT with access token headers.Authorization = `Bearer ${params.accessToken}` headers['Content-Type'] = 'text/plain' } @@ -112,20 +103,17 @@ export const uploadTool: ToolConfig const isExcelFile = params.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - // For file uploads or Excel creation, send all params as JSON to custom API route if (params.file || isExcelFile) { return { accessToken: params.accessToken, fileName: params.fileName, file: params.file, folderId: params.manualFolderId || params.folderSelector, - mimeType: params.mimeType, - // Optional Excel content write-after-create - values: params.values, + ...(params.mimeType && { mimeType: params.mimeType }), + ...(params.values && { values: params.values }), } } - // For text files, send content directly return (params.content || '') as unknown as Record }, }, @@ -136,7 +124,6 @@ export const uploadTool: ToolConfig const isExcelFile = params?.mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - // Handle response from custom API route (for file uploads or Excel creation) if ((params?.file || isExcelFile) && data.success !== undefined) { if (!data.success) { throw new Error(data.error || 'Failed to upload file') @@ -153,7 +140,6 @@ export const uploadTool: ToolConfig } } - // Handle response from direct Microsoft Graph API (for text-only uploads) const fileData = data logger.info('Successfully uploaded file to OneDrive', { diff --git a/apps/sim/tools/pipedrive/create_activity.ts b/apps/sim/tools/pipedrive/create_activity.ts index e1d2d57bec..906d1697b0 100644 --- a/apps/sim/tools/pipedrive/create_activity.ts +++ b/apps/sim/tools/pipedrive/create_activity.ts @@ -132,21 +132,8 @@ export const pipedriveCreateActivityTool: ToolConfig< }, outputs: { + activity: { type: 'object', description: 'The created activity object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created activity details', - properties: { - activity: { - type: 'object', - description: 'The created activity object', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/create_deal.ts b/apps/sim/tools/pipedrive/create_deal.ts index fd0ce4cf33..91c7798c0f 100644 --- a/apps/sim/tools/pipedrive/create_deal.ts +++ b/apps/sim/tools/pipedrive/create_deal.ts @@ -132,21 +132,8 @@ export const pipedriveCreateDealTool: ToolConfig< }, outputs: { + deal: { type: 'object', description: 'The created deal object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created deal details', - properties: { - deal: { - type: 'object', - description: 'The created deal object', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/create_lead.ts b/apps/sim/tools/pipedrive/create_lead.ts index 9cb6fc59ab..f7f1223d19 100644 --- a/apps/sim/tools/pipedrive/create_lead.ts +++ b/apps/sim/tools/pipedrive/create_lead.ts @@ -141,21 +141,8 @@ export const pipedriveCreateLeadTool: ToolConfig< }, outputs: { + lead: { type: 'object', description: 'The created lead object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created lead details', - properties: { - lead: { - type: 'object', - description: 'The created lead object', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/create_project.ts b/apps/sim/tools/pipedrive/create_project.ts index a3be010663..6673c4e404 100644 --- a/apps/sim/tools/pipedrive/create_project.ts +++ b/apps/sim/tools/pipedrive/create_project.ts @@ -97,21 +97,8 @@ export const pipedriveCreateProjectTool: ToolConfig< }, outputs: { + project: { type: 'object', description: 'The created project object' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Created project details', - properties: { - project: { - type: 'object', - description: 'The created project object', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/delete_lead.ts b/apps/sim/tools/pipedrive/delete_lead.ts index 9765e3ce0a..fcaee03f72 100644 --- a/apps/sim/tools/pipedrive/delete_lead.ts +++ b/apps/sim/tools/pipedrive/delete_lead.ts @@ -72,21 +72,8 @@ export const pipedriveDeleteLeadTool: ToolConfig< }, outputs: { + data: { type: 'object', description: 'Deletion confirmation data' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Deletion result', - properties: { - data: { - type: 'object', - description: 'Deletion confirmation data', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/get_activities.ts b/apps/sim/tools/pipedrive/get_activities.ts index b64fb3f2c1..2d0d3070b3 100644 --- a/apps/sim/tools/pipedrive/get_activities.ts +++ b/apps/sim/tools/pipedrive/get_activities.ts @@ -113,21 +113,8 @@ export const pipedriveGetActivitiesTool: ToolConfig< }, outputs: { + activities: { type: 'array', description: 'Array of activity objects from Pipedrive' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Activities data', - properties: { - activities: { - type: 'array', - description: 'Array of activity objects from Pipedrive', - }, - metadata: { - type: 'object', - description: 'Operation metadata', - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/get_all_deals.ts b/apps/sim/tools/pipedrive/get_all_deals.ts index 2c789e9da0..6c645f5880 100644 --- a/apps/sim/tools/pipedrive/get_all_deals.ts +++ b/apps/sim/tools/pipedrive/get_all_deals.ts @@ -118,44 +118,8 @@ export const pipedriveGetAllDealsTool: ToolConfig< }, outputs: { + deals: { type: 'array', description: 'Array of deal objects from Pipedrive' }, + metadata: { type: 'object', description: 'Operation metadata' }, success: { type: 'boolean', description: 'Operation success status' }, - output: { - type: 'object', - description: 'Deals data and metadata', - properties: { - deals: { - type: 'array', - description: 'Array of deal objects from Pipedrive', - items: { - type: 'object', - properties: { - id: { type: 'number', description: 'Deal ID' }, - title: { type: 'string', description: 'Deal title' }, - value: { type: 'number', description: 'Deal value' }, - currency: { type: 'string', description: 'Deal currency' }, - status: { type: 'string', description: 'Deal status' }, - stage_id: { type: 'number', description: 'Stage ID' }, - pipeline_id: { type: 'number', description: 'Pipeline ID' }, - owner_id: { type: 'number', description: 'Owner user ID' }, - add_time: { type: 'string', description: 'Deal creation time' }, - update_time: { type: 'string', description: 'Deal last update time' }, - }, - }, - }, - metadata: { - type: 'object', - description: 'Operation metadata', - properties: { - operation: { type: 'string', description: 'The operation performed' }, - totalItems: { type: 'number', description: 'Total number of deals returned' }, - hasMore: { - type: 'boolean', - description: 'Whether there are more items to fetch via pagination', - }, - }, - }, - success: { type: 'boolean', description: 'Operation success status' }, - }, - }, }, } diff --git a/apps/sim/tools/pipedrive/get_deal.ts b/apps/sim/tools/pipedrive/get_deal.ts index 1d4239166b..2733cfe284 100644 --- a/apps/sim/tools/pipedrive/get_deal.ts +++ b/apps/sim/tools/pipedrive/get_deal.ts @@ -61,21 +61,8 @@ export const pipedriveGetDealTool: ToolConfig = { confluence_update_comment: confluenceUpdateCommentTool, confluence_delete_comment: confluenceDeleteCommentTool, confluence_list_attachments: confluenceListAttachmentsTool, + confluence_upload_attachment: confluenceUploadAttachmentTool, confluence_delete_attachment: confluenceDeleteAttachmentTool, confluence_list_labels: confluenceListLabelsTool, confluence_get_space: confluenceGetSpaceTool, From 516dee14b7d5dc8a5b9f86b53996ea98328a1727 Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 18:55:53 -0800 Subject: [PATCH 08/34] feat(i18n): update translations (#2328) Co-authored-by: aadamgough --- apps/docs/content/docs/de/tools/apify.mdx | 6 +++--- apps/docs/content/docs/fr/tools/apify.mdx | 8 ++++---- apps/docs/content/docs/ja/tools/apify.mdx | 4 ++-- apps/docs/i18n.lock | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/docs/content/docs/de/tools/apify.mdx b/apps/docs/content/docs/de/tools/apify.mdx index cb8385055c..658cd8a4b2 100644 --- a/apps/docs/content/docs/de/tools/apify.mdx +++ b/apps/docs/content/docs/de/tools/apify.mdx @@ -51,9 +51,9 @@ Führe einen APIFY-Aktor synchron aus und erhalte Ergebnisse (maximal 5 Minuten) | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Ob die Aktor-Ausführung erfolgreich war | -| `runId` | string | APIFY-Ausführungs-ID | -| `status` | string | Ausführungsstatus \(SUCCEEDED, FAILED, usw.\) | +| `success` | boolean | Ob der Actor-Lauf erfolgreich war | +| `runId` | string | APIFY-Lauf-ID | +| `status` | string | Laufstatus \(SUCCEEDED, FAILED, usw.\) | | `items` | array | Dataset-Elemente \(falls abgeschlossen\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/fr/tools/apify.mdx b/apps/docs/content/docs/fr/tools/apify.mdx index 8010f2cad3..b318d92b31 100644 --- a/apps/docs/content/docs/fr/tools/apify.mdx +++ b/apps/docs/content/docs/fr/tools/apify.mdx @@ -51,10 +51,10 @@ Exécuter un acteur APIFY de manière synchrone et obtenir les résultats (maxim | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Indique si l'exécution de l'acteur a réussi | -| `runId` | chaîne | ID d'exécution APIFY | -| `status` | chaîne | Statut d'exécution \(SUCCEEDED, FAILED, etc.\) | -| `items` | tableau | Éléments du jeu de données \(si terminé\) | +| `success` | boolean | Indique si l'exécution de l'acteur a réussi | +| `runId` | string | ID d'exécution APIFY | +| `status` | string | Statut d'exécution \(SUCCEEDED, FAILED, etc.\) | +| `items` | array | Éléments du dataset \(si terminé\) | ### `apify_run_actor_async` diff --git a/apps/docs/content/docs/ja/tools/apify.mdx b/apps/docs/content/docs/ja/tools/apify.mdx index 04b4ae19d2..bd873bde51 100644 --- a/apps/docs/content/docs/ja/tools/apify.mdx +++ b/apps/docs/content/docs/ja/tools/apify.mdx @@ -51,9 +51,9 @@ APIPYアクターを同期的に実行して結果を取得(最大5分) | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | アクター実行が成功したかどうか | +| `success` | boolean | アクターの実行が成功したかどうか | | `runId` | string | APIFY実行ID | -| `status` | string | 実行ステータス(SUCCEEDED、FAILEDなど) | +| `status` | string | 実行ステータス(SUCCEEDED、FAILED、など) | | `items` | array | データセット項目(完了した場合) | ### `apify_run_actor_async` diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index 385b5cbe4b..2c1756375b 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -47473,7 +47473,7 @@ checksums: content/13: 371d0e46b4bd2c23f559b8bc112f6955 content/14: 6c217c31e3269045db51e0ca2e02dc40 content/15: bcadfc362b69078beee0088e5936c98b - content/16: 9a5ecda96a3113d95900df597cffc636 + content/16: cff09b9499de76d13da4478d7365dec2 content/17: e28cdc705de05af33fc86ed8d5d900d3 content/18: 0e38f19d9fbfbd36051d2e5c7f65d0c0 content/19: 371d0e46b4bd2c23f559b8bc112f6955 From 06d2db78ffff5966cfae6c2a8ba93a268e631ea0 Mon Sep 17 00:00:00 2001 From: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:35:26 -0800 Subject: [PATCH 09/34] improvement(kb): modals, page layouts (#2330) --- .../[workspaceId]/knowledge/[id]/base.tsx | 21 +++- .../add-documents-modal.tsx | 104 +++++++-------- .../create-base-modal/create-base-modal.tsx | 118 ++++++++++-------- 3 files changed, 136 insertions(+), 107 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx index fdc61e3d15..2c4ce5a3a8 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx @@ -928,9 +928,22 @@ export function KnowledgeBase({ Tags )} - + + + + + {!userPermissions.canEdit && ( + + Write permission required to delete knowledge base + + )} + @@ -940,7 +953,7 @@ export function KnowledgeBase({

)} -
+
{pagination.total} {pagination.total === 1 ? 'document' : 'documents'} diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-documents-modal/add-documents-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-documents-modal/add-documents-modal.tsx index 366d384f94..e88c79fe9e 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-documents-modal/add-documents-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-documents-modal/add-documents-modal.tsx @@ -1,7 +1,7 @@ 'use client' import { useEffect, useRef, useState } from 'react' -import { AlertCircle, Loader2, RotateCcw, X } from 'lucide-react' +import { Loader2, RotateCcw, X } from 'lucide-react' import { useParams } from 'next/navigation' import { Button, @@ -283,11 +283,11 @@ export function AddDocumentsModal({ return (
- {isFailed && !isRetrying && ( - + className={cn( + 'flex items-center gap-2 rounded-[4px] border p-[8px]', + isFailed && !isRetrying && 'border-[var(--text-error)]' )} + >
- {isFailed && !isRetrying && ( - - )} {isProcessing ? ( ) : ( - + <> + {isFailed && ( + + )} + + )}
@@ -336,30 +338,34 @@ export function AddDocumentsModal({
- - {uploadError && ( -

- {uploadError.message} -

- )} -
- - + +
+ {uploadError ? ( +

+ {uploadError.message} +

+ ) : ( +
+ )} +
+ + +
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx index 2362593b0d..d71a3641d7 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react' import { zodResolver } from '@hookform/resolvers/zod' -import { AlertCircle, Loader2, RotateCcw, X } from 'lucide-react' +import { Loader2, RotateCcw, X } from 'lucide-react' import { useParams } from 'next/navigation' import { useForm } from 'react-hook-form' import { z } from 'zod' @@ -449,11 +449,11 @@ export function CreateBaseModal({ return (
- {isFailed && !isRetrying && ( - + className={cn( + 'flex items-center gap-2 rounded-[4px] border p-[8px]', + isFailed && !isRetrying && 'border-[var(--text-error)]' )} + >
- {isFailed && !isRetrying && ( - - )} {isProcessing ? ( ) : ( - + <> + {isFailed && ( + + )} + + )}
@@ -509,32 +511,40 @@ export function CreateBaseModal({
- - {(submitStatus?.type === 'error' || uploadError) && ( -

- {uploadError?.message || submitStatus?.message} -

- )} -
- - + +
+ {submitStatus?.type === 'error' || uploadError ? ( +

+ {uploadError?.message || submitStatus?.message} +

+ ) : ( +
+ )} +
+ + +
From c4fd39df54f38abbce23a66ff8bb7ae4304baa9c Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 20:39:15 -0800 Subject: [PATCH 10/34] fix(firecrawl): fixed optional params for firecrawl (#2329) * fix(firecrawl): fixed optional params for firecrawl * fix(typeform): fixed optional params and outputs for typeform * ack PR comments --- apps/docs/components/icons.tsx | 58 +++++++++---------- apps/docs/components/ui/icon-mapping.ts | 2 +- apps/docs/content/docs/en/tools/asana.mdx | 36 ++++++++++-- .../docs/content/docs/en/tools/confluence.mdx | 27 +++++++++ .../content/docs/en/tools/google_groups.mdx | 24 ++++---- .../content/docs/en/tools/google_vault.mdx | 24 ++++---- apps/docs/content/docs/en/tools/hubspot.mdx | 43 ++++++++++---- apps/docs/content/docs/en/tools/pipedrive.mdx | 56 ++++++++++++------ apps/docs/content/docs/en/tools/sqs.mdx | 35 ++++++----- apps/docs/content/docs/en/tools/typeform.mdx | 48 +++++---------- .../components/tag-dropdown/tag-dropdown.tsx | 13 ++++- apps/sim/blocks/blocks/firecrawl.ts | 23 +++++++- apps/sim/blocks/blocks/typeform.ts | 17 +++--- apps/sim/tools/firecrawl/crawl.ts | 31 +++++----- apps/sim/tools/firecrawl/extract.ts | 19 +++--- apps/sim/tools/firecrawl/map.ts | 15 ++--- apps/sim/tools/firecrawl/scrape.ts | 37 ++++++------ apps/sim/tools/firecrawl/search.ts | 21 +++---- apps/sim/tools/typeform/create_form.ts | 26 +-------- apps/sim/tools/typeform/get_form.ts | 48 +++------------ apps/sim/tools/typeform/list_forms.ts | 31 +--------- apps/sim/tools/typeform/responses.ts | 16 +++++ apps/sim/tools/typeform/update_form.ts | 16 ++--- 23 files changed, 351 insertions(+), 315 deletions(-) diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index eca760cf55..6d7d5a7083 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -838,35 +838,6 @@ export const S3Icon = (props: SVGProps) => ( ) -export function SQSIcon(props: SVGProps) { - return ( - - - - - - - - ) -} - export function GoogleIcon(props: SVGProps) { return ( @@ -3931,6 +3902,35 @@ export function DynamoDBIcon(props: SVGProps) { ) } +export function SQSIcon(props: SVGProps) { + return ( + + + + + + + + ) +} + export function McpIcon(props: SVGProps) { return ( = { stagehand_agent: StagehandIcon, stagehand: StagehandIcon, ssh: SshIcon, + sqs: SQSIcon, smtp: SmtpIcon, slack: SlackIcon, shopify: ShopifyIcon, @@ -216,7 +217,6 @@ export const blockTypeToIconMap: Record = { elevenlabs: ElevenLabsIcon, elasticsearch: ElasticsearchIcon, dynamodb: DynamoDBIcon, - sqs: SQSIcon, duckduckgo: DuckDuckGoIcon, dropbox: DropboxIcon, discord: DiscordIcon, diff --git a/apps/docs/content/docs/en/tools/asana.mdx b/apps/docs/content/docs/en/tools/asana.mdx index 1822a1a4d8..87686e065c 100644 --- a/apps/docs/content/docs/en/tools/asana.mdx +++ b/apps/docs/content/docs/en/tools/asana.mdx @@ -36,7 +36,14 @@ Retrieve a single task by GID or get multiple tasks with filters | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | Single task details or array of tasks, depending on whether taskGid was provided | +| `ts` | string | Timestamp of the response | +| `gid` | string | Task globally unique identifier | +| `resource_type` | string | Resource type \(task\) | +| `resource_subtype` | string | Resource subtype | +| `name` | string | Task name | +| `notes` | string | Task notes or description | +| `completed` | boolean | Whether the task is completed | +| `assignee` | object | Assignee details | ### `asana_create_task` @@ -57,7 +64,13 @@ Create a new task in Asana | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | Created task details with timestamp, gid, name, notes, and permalink | +| `ts` | string | Timestamp of the response | +| `gid` | string | Task globally unique identifier | +| `name` | string | Task name | +| `notes` | string | Task notes or description | +| `completed` | boolean | Whether the task is completed | +| `created_at` | string | Task creation timestamp | +| `permalink_url` | string | URL to the task in Asana | ### `asana_update_task` @@ -79,7 +92,12 @@ Update an existing task in Asana | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | Updated task details with timestamp, gid, name, notes, and modified timestamp | +| `ts` | string | Timestamp of the response | +| `gid` | string | Task globally unique identifier | +| `name` | string | Task name | +| `notes` | string | Task notes or description | +| `completed` | boolean | Whether the task is completed | +| `modified_at` | string | Task last modified timestamp | ### `asana_get_projects` @@ -96,7 +114,8 @@ Retrieve all projects from an Asana workspace | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | List of projects with their gid, name, and resource type | +| `ts` | string | Timestamp of the response | +| `projects` | array | Array of projects | ### `asana_search_tasks` @@ -117,7 +136,8 @@ Search for tasks in an Asana workspace | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | List of tasks matching the search criteria | +| `ts` | string | Timestamp of the response | +| `tasks` | array | Array of matching tasks | ### `asana_add_comment` @@ -135,7 +155,11 @@ Add a comment (story) to an Asana task | Parameter | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Operation success status | -| `output` | object | Comment details including gid, text, created timestamp, and author | +| `ts` | string | Timestamp of the response | +| `gid` | string | Comment globally unique identifier | +| `text` | string | Comment text content | +| `created_at` | string | Comment creation timestamp | +| `created_by` | object | Comment author details | diff --git a/apps/docs/content/docs/en/tools/confluence.mdx b/apps/docs/content/docs/en/tools/confluence.mdx index c40551652d..031ef7f908 100644 --- a/apps/docs/content/docs/en/tools/confluence.mdx +++ b/apps/docs/content/docs/en/tools/confluence.mdx @@ -224,6 +224,33 @@ Delete a comment from a Confluence page. | `commentId` | string | Deleted comment ID | | `deleted` | boolean | Deletion status | +### `confluence_upload_attachment` + +Upload a file as an attachment to a Confluence page. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `domain` | string | Yes | Your Confluence domain \(e.g., yourcompany.atlassian.net\) | +| `pageId` | string | Yes | Confluence page ID to attach the file to | +| `file` | file | Yes | The file to upload as an attachment | +| `fileName` | string | No | Optional custom file name for the attachment | +| `comment` | string | No | Optional comment to add to the attachment | +| `cloudId` | string | No | Confluence Cloud ID for the instance. If not provided, it will be fetched using the domain. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ts` | string | Timestamp of upload | +| `attachmentId` | string | Uploaded attachment ID | +| `title` | string | Attachment file name | +| `fileSize` | number | File size in bytes | +| `mediaType` | string | MIME type of the attachment | +| `downloadUrl` | string | Download URL for the attachment | +| `pageId` | string | Page ID the attachment was added to | + ### `confluence_list_attachments` List all attachments on a Confluence page. diff --git a/apps/docs/content/docs/en/tools/google_groups.mdx b/apps/docs/content/docs/en/tools/google_groups.mdx index 727ab72711..e6dc141c4a 100644 --- a/apps/docs/content/docs/en/tools/google_groups.mdx +++ b/apps/docs/content/docs/en/tools/google_groups.mdx @@ -36,7 +36,8 @@ List all groups in a Google Workspace domain | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `groups` | json | Array of group objects | +| `nextPageToken` | string | Token for fetching next page of results | ### `google_groups_get_group` @@ -52,7 +53,7 @@ Get details of a specific Google Group by email or group ID | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `group` | json | Group object | ### `google_groups_create_group` @@ -70,7 +71,7 @@ Create a new Google Group in the domain | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `group` | json | Created group object | ### `google_groups_update_group` @@ -89,7 +90,7 @@ Update an existing Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `group` | json | Updated group object | ### `google_groups_delete_group` @@ -105,7 +106,7 @@ Delete a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `message` | string | Success message | ### `google_groups_list_members` @@ -124,7 +125,8 @@ List all members of a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `members` | json | Array of member objects | +| `nextPageToken` | string | Token for fetching next page of results | ### `google_groups_get_member` @@ -141,7 +143,7 @@ Get details of a specific member in a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `member` | json | Member object | ### `google_groups_add_member` @@ -159,7 +161,7 @@ Add a new member to a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `member` | json | Added member object | ### `google_groups_remove_member` @@ -176,7 +178,7 @@ Remove a member from a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `message` | string | Success message | ### `google_groups_update_member` @@ -194,7 +196,7 @@ Update a member | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `member` | json | Updated member object | ### `google_groups_has_member` @@ -211,7 +213,7 @@ Check if a user is a member of a Google Group | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Google Groups API response data | +| `isMember` | boolean | Whether the user is a member of the group | diff --git a/apps/docs/content/docs/en/tools/google_vault.mdx b/apps/docs/content/docs/en/tools/google_vault.mdx index 34d0394585..39714d1122 100644 --- a/apps/docs/content/docs/en/tools/google_vault.mdx +++ b/apps/docs/content/docs/en/tools/google_vault.mdx @@ -36,8 +36,7 @@ Create an export in a matter | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `export` | json | Created export object | ### `google_vault_list_matters_export` @@ -56,8 +55,9 @@ List exports for a matter | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `exports` | json | Array of export objects | +| `export` | json | Single export object \(when exportId is provided\) | +| `nextPageToken` | string | Token for fetching next page of results | ### `google_vault_download_export_file` @@ -96,8 +96,7 @@ Create a hold in a matter | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `hold` | json | Created hold object | ### `google_vault_list_matters_holds` @@ -116,8 +115,9 @@ List holds for a matter | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `holds` | json | Array of hold objects | +| `hold` | json | Single hold object \(when holdId is provided\) | +| `nextPageToken` | string | Token for fetching next page of results | ### `google_vault_create_matters` @@ -134,8 +134,7 @@ Create a new matter in Google Vault | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `matter` | json | Created matter object | ### `google_vault_list_matters` @@ -153,8 +152,9 @@ List matters, or get a specific matter if matterId is provided | Parameter | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Vault API response data | -| `file` | json | Downloaded export file \(UserFile\) from execution files | +| `matters` | json | Array of matter objects | +| `matter` | json | Single matter object \(when matterId is provided\) | +| `nextPageToken` | string | Token for fetching next page of results | diff --git a/apps/docs/content/docs/en/tools/hubspot.mdx b/apps/docs/content/docs/en/tools/hubspot.mdx index cd673afbe3..a1e64a9cec 100644 --- a/apps/docs/content/docs/en/tools/hubspot.mdx +++ b/apps/docs/content/docs/en/tools/hubspot.mdx @@ -50,8 +50,9 @@ Retrieve all users from HubSpot account | Parameter | Type | Description | | --------- | ---- | ----------- | +| `users` | array | Array of HubSpot user objects | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Users data | ### `hubspot_list_contacts` @@ -70,8 +71,10 @@ Retrieve all contacts from HubSpot account with pagination support | Parameter | Type | Description | | --------- | ---- | ----------- | +| `contacts` | array | Array of HubSpot contact objects | +| `paging` | object | Pagination information | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Contacts data | ### `hubspot_get_contact` @@ -90,8 +93,9 @@ Retrieve a single contact by ID or email from HubSpot | Parameter | Type | Description | | --------- | ---- | ----------- | +| `contact` | object | HubSpot contact object with properties | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Contact data | ### `hubspot_create_contact` @@ -108,8 +112,9 @@ Create a new contact in HubSpot. Requires at least one of: email, firstname, or | Parameter | Type | Description | | --------- | ---- | ----------- | +| `contact` | object | Created HubSpot contact object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created contact data | ### `hubspot_update_contact` @@ -127,8 +132,9 @@ Update an existing contact in HubSpot by ID or email | Parameter | Type | Description | | --------- | ---- | ----------- | +| `contact` | object | Updated HubSpot contact object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Updated contact data | ### `hubspot_search_contacts` @@ -149,8 +155,11 @@ Search for contacts in HubSpot using filters, sorting, and queries | Parameter | Type | Description | | --------- | ---- | ----------- | +| `contacts` | array | Array of matching HubSpot contact objects | +| `total` | number | Total number of matching contacts | +| `paging` | object | Pagination information | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Search results | ### `hubspot_list_companies` @@ -169,8 +178,10 @@ Retrieve all companies from HubSpot account with pagination support | Parameter | Type | Description | | --------- | ---- | ----------- | +| `companies` | array | Array of HubSpot company objects | +| `paging` | object | Pagination information | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Companies data | ### `hubspot_get_company` @@ -189,8 +200,9 @@ Retrieve a single company by ID or domain from HubSpot | Parameter | Type | Description | | --------- | ---- | ----------- | +| `company` | object | HubSpot company object with properties | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Company data | ### `hubspot_create_company` @@ -207,8 +219,9 @@ Create a new company in HubSpot | Parameter | Type | Description | | --------- | ---- | ----------- | +| `company` | object | Created HubSpot company object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created company data | ### `hubspot_update_company` @@ -226,8 +239,9 @@ Update an existing company in HubSpot by ID or domain | Parameter | Type | Description | | --------- | ---- | ----------- | +| `company` | object | Updated HubSpot company object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Updated company data | ### `hubspot_search_companies` @@ -248,8 +262,11 @@ Search for companies in HubSpot using filters, sorting, and queries | Parameter | Type | Description | | --------- | ---- | ----------- | +| `companies` | array | Array of matching HubSpot company objects | +| `total` | number | Total number of matching companies | +| `paging` | object | Pagination information | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Search results | ### `hubspot_list_deals` @@ -268,8 +285,10 @@ Retrieve all deals from HubSpot account with pagination support | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Array of HubSpot deal objects | +| `paging` | object | Pagination information | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Deals data | diff --git a/apps/docs/content/docs/en/tools/pipedrive.mdx b/apps/docs/content/docs/en/tools/pipedrive.mdx index 88d05a1c48..3f66973c8b 100644 --- a/apps/docs/content/docs/en/tools/pipedrive.mdx +++ b/apps/docs/content/docs/en/tools/pipedrive.mdx @@ -54,8 +54,9 @@ Retrieve all deals from Pipedrive with optional filters | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Array of deal objects from Pipedrive | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Deals data and metadata | ### `pipedrive_get_deal` @@ -71,8 +72,9 @@ Retrieve detailed information about a specific deal | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | Deal object with full details | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Deal details | ### `pipedrive_create_deal` @@ -96,8 +98,9 @@ Create a new deal in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | The created deal object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created deal details | ### `pipedrive_update_deal` @@ -118,8 +121,9 @@ Update an existing deal in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | The updated deal object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Updated deal details | ### `pipedrive_get_files` @@ -138,8 +142,9 @@ Retrieve files from Pipedrive with optional filters | Parameter | Type | Description | | --------- | ---- | ----------- | +| `files` | array | Array of file objects from Pipedrive | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Files data | ### `pipedrive_get_mail_messages` @@ -156,8 +161,9 @@ Retrieve mail threads from Pipedrive mailbox | Parameter | Type | Description | | --------- | ---- | ----------- | +| `messages` | array | Array of mail thread objects from Pipedrive mailbox | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Mail threads data | ### `pipedrive_get_mail_thread` @@ -173,8 +179,9 @@ Retrieve all messages from a specific mail thread | Parameter | Type | Description | | --------- | ---- | ----------- | +| `messages` | array | Array of mail message objects from the thread | +| `metadata` | object | Operation metadata including thread ID | | `success` | boolean | Operation success status | -| `output` | object | Mail thread messages data | ### `pipedrive_get_pipelines` @@ -193,8 +200,9 @@ Retrieve all pipelines from Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `pipelines` | array | Array of pipeline objects from Pipedrive | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Pipelines data | ### `pipedrive_get_pipeline_deals` @@ -213,8 +221,9 @@ Retrieve all deals in a specific pipeline | Parameter | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Array of deal objects from the pipeline | +| `metadata` | object | Operation metadata including pipeline ID | | `success` | boolean | Operation success status | -| `output` | object | Pipeline deals data | ### `pipedrive_get_projects` @@ -232,8 +241,10 @@ Retrieve all projects or a specific project from Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `projects` | array | Array of project objects \(when listing all\) | +| `project` | object | Single project object \(when project_id is provided\) | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Projects data or single project details | ### `pipedrive_create_project` @@ -252,8 +263,9 @@ Create a new project in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `project` | object | The created project object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created project details | ### `pipedrive_get_activities` @@ -274,8 +286,9 @@ Retrieve activities (tasks) from Pipedrive with optional filters | Parameter | Type | Description | | --------- | ---- | ----------- | +| `activities` | array | Array of activity objects from Pipedrive | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Activities data | ### `pipedrive_create_activity` @@ -299,8 +312,9 @@ Create a new activity (task) in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `activity` | object | The created activity object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created activity details | ### `pipedrive_update_activity` @@ -322,8 +336,9 @@ Update an existing activity (task) in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `activity` | object | The updated activity object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Updated activity details | ### `pipedrive_get_leads` @@ -344,8 +359,10 @@ Retrieve all leads or a specific lead from Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `leads` | array | Array of lead objects \(when listing all\) | +| `lead` | object | Single lead object \(when lead_id is provided\) | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Leads data or single lead details | ### `pipedrive_create_lead` @@ -368,8 +385,9 @@ Create a new lead in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `lead` | object | The created lead object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Created lead details | ### `pipedrive_update_lead` @@ -393,8 +411,9 @@ Update an existing lead in Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `lead` | object | The updated lead object | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Updated lead details | ### `pipedrive_delete_lead` @@ -410,8 +429,9 @@ Delete a specific lead from Pipedrive | Parameter | Type | Description | | --------- | ---- | ----------- | +| `data` | object | Deletion confirmation data | +| `metadata` | object | Operation metadata | | `success` | boolean | Operation success status | -| `output` | object | Deletion result | diff --git a/apps/docs/content/docs/en/tools/sqs.mdx b/apps/docs/content/docs/en/tools/sqs.mdx index a4c368b63f..0fe60e5425 100644 --- a/apps/docs/content/docs/en/tools/sqs.mdx +++ b/apps/docs/content/docs/en/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: Connect to Amazon SQS --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -28,10 +28,13 @@ In Sim, the SQS integration enables your agents to send messages to Amazon SQS q This integration allows your agents to automate message sending workflows without manual intervention. By connecting Sim with Amazon SQS, you can build agents that publish messages to queues within your workflows—all without handling queue infrastructure or connections. {/* MANUAL-CONTENT-END */} + ## Usage Instructions Integrate Amazon SQS into the workflow. Can send messages to SQS queues. + + ## Tools ### `sqs_send` @@ -40,22 +43,24 @@ Send a message to an Amazon SQS queue #### Input -| Parameter | Type | Required | Description | -| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | -| `region` | string | Yes | AWS region \(e.g., us-east-1\) | -| `accessKeyId` | string | Yes | AWS access key ID | -| `secretAccessKey` | string | Yes | AWS secret access key | -| `queueUrl` | string | Yes | Queue URL \(e.g., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | -| `data` | object | Yes | Message body to send as JSON object | -| `messageGroupId` | string | No | Message group ID \(optional\) | -| `messageDeduplicationId` | string | No | Message deduplication ID for FIFO queues \(optional\) | +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `queueUrl` | string | Yes | Queue URL | +| `data` | object | Yes | Message body to send | +| `messageGroupId` | string | No | Message group ID \(optional\) | +| `messageDeduplicationId` | string | No | Message deduplication ID \(optional\) | #### Output -| Parameter | Type | Description | -| --------- | ------ | --------------------------------------------------------- | -| `message` | string | Success or error message describing the operation outcome | -| `id` | string | Message ID | +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `id` | string | Message ID | + + ## Notes diff --git a/apps/docs/content/docs/en/tools/typeform.mdx b/apps/docs/content/docs/en/tools/typeform.mdx index 7aa4f4ca33..829fc64613 100644 --- a/apps/docs/content/docs/en/tools/typeform.mdx +++ b/apps/docs/content/docs/en/tools/typeform.mdx @@ -51,25 +51,9 @@ Retrieve form responses from Typeform | Parameter | Type | Description | | --------- | ---- | ----------- | -| `total_items` | number | Total response/form count | -| `page_count` | number | Total page count | -| `items` | json | Response/form items array | -| `id` | string | Form unique identifier | -| `title` | string | Form title | -| `type` | string | Form type | -| `created_at` | string | ISO timestamp of form creation | -| `last_updated_at` | string | ISO timestamp of last update | -| `settings` | json | Form settings object | -| `theme` | json | Theme configuration object | -| `workspace` | json | Workspace information | -| `fields` | json | Form fields/questions array | -| `thankyou_screens` | json | Thank you screens array | -| `_links` | json | Related resource links | -| `deleted` | boolean | Whether the form was successfully deleted | -| `message` | string | Deletion confirmation message | -| `fileUrl` | string | Downloaded file URL | -| `contentType` | string | File content type | -| `filename` | string | File name | +| `total_items` | number | Total number of responses | +| `page_count` | number | Total number of pages available | +| `items` | array | Array of response objects with response_id, submitted_at, answers, and metadata | ### `typeform_files` @@ -131,7 +115,7 @@ Retrieve a list of all forms in your Typeform account | --------- | ---- | ----------- | | `total_items` | number | Total number of forms in the account | | `page_count` | number | Total number of pages available | -| `items` | array | Array of form objects | +| `items` | array | Array of form objects with id, title, created_at, last_updated_at, settings, theme, and _links | ### `typeform_get_form` @@ -151,11 +135,13 @@ Retrieve complete details and structure of a specific form | `id` | string | Form unique identifier | | `title` | string | Form title | | `type` | string | Form type \(form, quiz, etc.\) | -| `created_at` | string | ISO timestamp of form creation | -| `last_updated_at` | string | ISO timestamp of last update | | `settings` | object | Form settings including language, progress bar, etc. | -| `theme` | object | Theme configuration with colors, fonts, and design settings | -| `workspace` | object | Workspace information | +| `theme` | object | Theme reference | +| `workspace` | object | Workspace reference | +| `fields` | array | Array of form fields/questions | +| `welcome_screens` | array | Array of welcome screens | +| `thankyou_screens` | array | Array of thank you screens | +| `_links` | object | Related resource links including public form URL | ### `typeform_create_form` @@ -180,13 +166,8 @@ Create a new form with fields and settings | `id` | string | Created form unique identifier | | `title` | string | Form title | | `type` | string | Form type | -| `created_at` | string | ISO timestamp of form creation | -| `last_updated_at` | string | ISO timestamp of last update | -| `settings` | object | Form settings | -| `theme` | object | Applied theme configuration | -| `workspace` | object | Workspace information | | `fields` | array | Array of created form fields | -| `_links` | object | Related resource links | +| `_links` | object | Related resource links including public form URL | ### `typeform_update_form` @@ -207,12 +188,11 @@ Update an existing form using JSON Patch operations | `id` | string | Updated form unique identifier | | `title` | string | Form title | | `type` | string | Form type | -| `created_at` | string | ISO timestamp of form creation | -| `last_updated_at` | string | ISO timestamp of last update | | `settings` | object | Form settings | -| `theme` | object | Theme configuration | -| `workspace` | object | Workspace information | +| `theme` | object | Theme reference | +| `workspace` | object | Workspace reference | | `fields` | array | Array of form fields | +| `welcome_screens` | array | Array of welcome screens | | `thankyou_screens` | array | Array of thank you screens | | `_links` | object | Related resource links | diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx index e630e5bdc1..dcdf3e638d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx @@ -206,7 +206,18 @@ const generateOutputPaths = (outputs: Record, prefix = ''): string[ paths.push(currentPath) } else if (typeof value === 'object' && value !== null) { if ('type' in value && typeof value.type === 'string') { - paths.push(currentPath) + const hasNestedProperties = + (value.type === 'object' && value.properties) || + (value.type === 'array' && value.items?.properties) || + (value.type === 'array' && + value.items && + typeof value.items === 'object' && + !('type' in value.items)) + + if (!hasNestedProperties) { + paths.push(currentPath) + } + if (value.type === 'object' && value.properties) { paths.push(...generateOutputPaths(value.properties, currentPath)) } else if (value.type === 'array' && value.items?.properties) { diff --git a/apps/sim/blocks/blocks/firecrawl.ts b/apps/sim/blocks/blocks/firecrawl.ts index dc66c82773..13706951c9 100644 --- a/apps/sim/blocks/blocks/firecrawl.ts +++ b/apps/sim/blocks/blocks/firecrawl.ts @@ -182,12 +182,20 @@ export const FirecrawlBlock: BlockConfig = { const result: Record = { apiKey } - // Handle operation-specific fields switch (operation) { case 'scrape': if (url) result.url = url if (formats) { - result.formats = Array.isArray(formats) ? formats : ['markdown'] + if (Array.isArray(formats)) { + result.formats = formats + } else if (typeof formats === 'string') { + try { + const parsed = JSON.parse(formats) + result.formats = Array.isArray(parsed) ? parsed : ['markdown'] + } catch { + result.formats = ['markdown'] + } + } } if (timeout) result.timeout = Number.parseInt(timeout) if (waitFor) result.waitFor = Number.parseInt(waitFor) @@ -214,7 +222,16 @@ export const FirecrawlBlock: BlockConfig = { case 'extract': if (urls) { - result.urls = Array.isArray(urls) ? urls : [urls] + if (Array.isArray(urls)) { + result.urls = urls + } else if (typeof urls === 'string') { + try { + const parsed = JSON.parse(urls) + result.urls = Array.isArray(parsed) ? parsed : [parsed] + } catch { + result.urls = [urls] + } + } } if (prompt) result.prompt = prompt break diff --git a/apps/sim/blocks/blocks/typeform.ts b/apps/sim/blocks/blocks/typeform.ts index 7e5c6d8773..e8648d0783 100644 --- a/apps/sim/blocks/blocks/typeform.ts +++ b/apps/sim/blocks/blocks/typeform.ts @@ -308,29 +308,30 @@ export const TypeformBlock: BlockConfig = { operations: { type: 'json', description: 'JSON Patch operations array' }, }, outputs: { - // Common outputs (used by responses, list_forms) + // List/responses outputs total_items: { type: 'number', description: 'Total response/form count' }, page_count: { type: 'number', description: 'Total page count' }, items: { type: 'json', description: 'Response/form items array' }, - // Form details outputs (get_form, create_form, update_form) + // Form details outputs id: { type: 'string', description: 'Form unique identifier' }, title: { type: 'string', description: 'Form title' }, type: { type: 'string', description: 'Form type' }, - created_at: { type: 'string', description: 'ISO timestamp of form creation' }, - last_updated_at: { type: 'string', description: 'ISO timestamp of last update' }, settings: { type: 'json', description: 'Form settings object' }, - theme: { type: 'json', description: 'Theme configuration object' }, - workspace: { type: 'json', description: 'Workspace information' }, - fields: { type: 'json', description: 'Form fields/questions array' }, + theme: { type: 'json', description: 'Theme reference' }, + workspace: { type: 'json', description: 'Workspace reference' }, + fields: { type: 'json', description: 'Form fields array' }, + welcome_screens: { type: 'json', description: 'Welcome screens array' }, thankyou_screens: { type: 'json', description: 'Thank you screens array' }, _links: { type: 'json', description: 'Related resource links' }, // Delete form outputs - deleted: { type: 'boolean', description: 'Whether the form was successfully deleted' }, + deleted: { type: 'boolean', description: 'Whether the form was deleted' }, message: { type: 'string', description: 'Deletion confirmation message' }, // File operation outputs fileUrl: { type: 'string', description: 'Downloaded file URL' }, contentType: { type: 'string', description: 'File content type' }, filename: { type: 'string', description: 'File name' }, + // Insights outputs + form: { type: 'json', description: 'Form analytics and performance data' }, }, triggers: { enabled: true, diff --git a/apps/sim/tools/firecrawl/crawl.ts b/apps/sim/tools/firecrawl/crawl.ts index a4651d92d8..335ee4c342 100644 --- a/apps/sim/tools/firecrawl/crawl.ts +++ b/apps/sim/tools/firecrawl/crawl.ts @@ -55,23 +55,24 @@ export const crawlTool: ToolConfig }, } - // Add all optional crawl-specific parameters if provided - if (params.prompt !== undefined) body.prompt = params.prompt - if (params.maxDiscoveryDepth !== undefined) - body.maxDiscoveryDepth = Number(params.maxDiscoveryDepth) - if (params.sitemap !== undefined) body.sitemap = params.sitemap - if (params.crawlEntireDomain !== undefined) body.crawlEntireDomain = params.crawlEntireDomain - if (params.allowExternalLinks !== undefined) + if (params.prompt) body.prompt = params.prompt + if (params.maxDiscoveryDepth) body.maxDiscoveryDepth = Number(params.maxDiscoveryDepth) + if (params.sitemap) body.sitemap = params.sitemap + if (typeof params.crawlEntireDomain === 'boolean') + body.crawlEntireDomain = params.crawlEntireDomain + if (typeof params.allowExternalLinks === 'boolean') body.allowExternalLinks = params.allowExternalLinks - if (params.allowSubdomains !== undefined) body.allowSubdomains = params.allowSubdomains - if (params.ignoreQueryParameters !== undefined) + if (typeof params.allowSubdomains === 'boolean') body.allowSubdomains = params.allowSubdomains + if (typeof params.ignoreQueryParameters === 'boolean') body.ignoreQueryParameters = params.ignoreQueryParameters - if (params.delay !== undefined) body.delay = Number(params.delay) - if (params.maxConcurrency !== undefined) body.maxConcurrency = Number(params.maxConcurrency) - if (params.excludePaths !== undefined) body.excludePaths = params.excludePaths - if (params.includePaths !== undefined) body.includePaths = params.includePaths - if (params.webhook !== undefined) body.webhook = params.webhook - if (params.zeroDataRetention !== undefined) body.zeroDataRetention = params.zeroDataRetention + if (params.delay != null && params.delay !== '') body.delay = Number(params.delay) + if (params.maxConcurrency != null && params.maxConcurrency !== '') + body.maxConcurrency = Number(params.maxConcurrency) + if (params.excludePaths) body.excludePaths = params.excludePaths + if (params.includePaths) body.includePaths = params.includePaths + if (params.webhook) body.webhook = params.webhook + if (typeof params.zeroDataRetention === 'boolean') + body.zeroDataRetention = params.zeroDataRetention return body }, diff --git a/apps/sim/tools/firecrawl/extract.ts b/apps/sim/tools/firecrawl/extract.ts index e1c80b8bed..0f79987048 100644 --- a/apps/sim/tools/firecrawl/extract.ts +++ b/apps/sim/tools/firecrawl/extract.ts @@ -89,15 +89,16 @@ export const extractTool: ToolConfig = { urls: params.urls, } - if (params.prompt != null) body.prompt = params.prompt - if (params.schema != null) body.schema = params.schema - if (params.enableWebSearch != null) body.enableWebSearch = params.enableWebSearch - if (params.ignoreSitemap != null) body.ignoreSitemap = params.ignoreSitemap - if (params.includeSubdomains != null) body.includeSubdomains = params.includeSubdomains - if (params.showSources != null) body.showSources = params.showSources - if (params.ignoreInvalidURLs != null) body.ignoreInvalidURLs = params.ignoreInvalidURLs - - // Add scrapeOptions, filtering out null/undefined values + if (params.prompt) body.prompt = params.prompt + if (params.schema) body.schema = params.schema + if (typeof params.enableWebSearch === 'boolean') body.enableWebSearch = params.enableWebSearch + if (typeof params.ignoreSitemap === 'boolean') body.ignoreSitemap = params.ignoreSitemap + if (typeof params.includeSubdomains === 'boolean') + body.includeSubdomains = params.includeSubdomains + if (typeof params.showSources === 'boolean') body.showSources = params.showSources + if (typeof params.ignoreInvalidURLs === 'boolean') + body.ignoreInvalidURLs = params.ignoreInvalidURLs + if (params.scrapeOptions != null) { const cleanedScrapeOptions = Object.entries(params.scrapeOptions).reduce( (acc, [key, val]) => { diff --git a/apps/sim/tools/firecrawl/map.ts b/apps/sim/tools/firecrawl/map.ts index 0e139c7efa..033e2861ed 100644 --- a/apps/sim/tools/firecrawl/map.ts +++ b/apps/sim/tools/firecrawl/map.ts @@ -77,14 +77,15 @@ export const mapTool: ToolConfig = { url: params.url, } - if (params.search != null) body.search = params.search - if (params.sitemap != null) body.sitemap = params.sitemap - if (params.includeSubdomains != null) body.includeSubdomains = params.includeSubdomains - if (params.ignoreQueryParameters != null) + if (params.search) body.search = params.search + if (params.sitemap) body.sitemap = params.sitemap + if (typeof params.includeSubdomains === 'boolean') + body.includeSubdomains = params.includeSubdomains + if (typeof params.ignoreQueryParameters === 'boolean') body.ignoreQueryParameters = params.ignoreQueryParameters - if (params.limit !== undefined) body.limit = Number(params.limit) - if (params.timeout !== undefined) body.timeout = Number(params.timeout) - if (params.location !== undefined) body.location = params.location + if (params.limit != null && params.limit !== '') body.limit = Number(params.limit) + if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (params.location) body.location = params.location return body }, diff --git a/apps/sim/tools/firecrawl/scrape.ts b/apps/sim/tools/firecrawl/scrape.ts index 9530cca28b..18814132fb 100644 --- a/apps/sim/tools/firecrawl/scrape.ts +++ b/apps/sim/tools/firecrawl/scrape.ts @@ -42,28 +42,27 @@ export const scrapeTool: ToolConfig = { formats: params.formats || params.scrapeOptions?.formats || ['markdown'], } - // Add all optional top-level parameters if provided - if (params.onlyMainContent !== undefined) body.onlyMainContent = params.onlyMainContent - if (params.includeTags !== undefined) body.includeTags = params.includeTags - if (params.excludeTags !== undefined) body.excludeTags = params.excludeTags - if (params.maxAge !== undefined) body.maxAge = Number(params.maxAge) - if (params.headers !== undefined) body.headers = params.headers - if (params.waitFor !== undefined) body.waitFor = Number(params.waitFor) - if (params.mobile !== undefined) body.mobile = params.mobile - if (params.skipTlsVerification !== undefined) + if (typeof params.onlyMainContent === 'boolean') body.onlyMainContent = params.onlyMainContent + if (params.includeTags) body.includeTags = params.includeTags + if (params.excludeTags) body.excludeTags = params.excludeTags + if (params.maxAge != null && params.maxAge !== '') body.maxAge = Number(params.maxAge) + if (params.headers) body.headers = params.headers + if (params.waitFor != null && params.waitFor !== '') body.waitFor = Number(params.waitFor) + if (typeof params.mobile === 'boolean') body.mobile = params.mobile + if (typeof params.skipTlsVerification === 'boolean') body.skipTlsVerification = params.skipTlsVerification - if (params.timeout !== undefined) body.timeout = Number(params.timeout) - if (params.parsers !== undefined) body.parsers = params.parsers - if (params.actions !== undefined) body.actions = params.actions - if (params.location !== undefined) body.location = params.location - if (params.removeBase64Images !== undefined) + if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (params.parsers) body.parsers = params.parsers + if (params.actions) body.actions = params.actions + if (params.location) body.location = params.location + if (typeof params.removeBase64Images === 'boolean') body.removeBase64Images = params.removeBase64Images - if (params.blockAds !== undefined) body.blockAds = params.blockAds - if (params.proxy !== undefined) body.proxy = params.proxy - if (params.storeInCache !== undefined) body.storeInCache = params.storeInCache - if (params.zeroDataRetention !== undefined) body.zeroDataRetention = params.zeroDataRetention + if (typeof params.blockAds === 'boolean') body.blockAds = params.blockAds + if (params.proxy) body.proxy = params.proxy + if (typeof params.storeInCache === 'boolean') body.storeInCache = params.storeInCache + if (typeof params.zeroDataRetention === 'boolean') + body.zeroDataRetention = params.zeroDataRetention - // Support legacy scrapeOptions for backwards compatibility if (params.scrapeOptions) { Object.assign(body, params.scrapeOptions) } diff --git a/apps/sim/tools/firecrawl/search.ts b/apps/sim/tools/firecrawl/search.ts index 376d4bd5c1..bf7b112e7b 100644 --- a/apps/sim/tools/firecrawl/search.ts +++ b/apps/sim/tools/firecrawl/search.ts @@ -34,16 +34,17 @@ export const searchTool: ToolConfig = { query: params.query, } - // Add all optional parameters if provided - if (params.limit !== undefined) body.limit = Number(params.limit) - if (params.sources !== undefined) body.sources = params.sources - if (params.categories !== undefined) body.categories = params.categories - if (params.tbs !== undefined) body.tbs = params.tbs - if (params.location !== undefined) body.location = params.location - if (params.country !== undefined) body.country = params.country - if (params.timeout !== undefined) body.timeout = Number(params.timeout) - if (params.ignoreInvalidURLs !== undefined) body.ignoreInvalidURLs = params.ignoreInvalidURLs - if (params.scrapeOptions !== undefined) body.scrapeOptions = params.scrapeOptions + // Add optional parameters if provided (truthy check filters empty strings, null, undefined) + if (params.limit != null && params.limit !== '') body.limit = Number(params.limit) + if (params.sources) body.sources = params.sources + if (params.categories) body.categories = params.categories + if (params.tbs) body.tbs = params.tbs + if (params.location) body.location = params.location + if (params.country) body.country = params.country + if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (typeof params.ignoreInvalidURLs === 'boolean') + body.ignoreInvalidURLs = params.ignoreInvalidURLs + if (params.scrapeOptions) body.scrapeOptions = params.scrapeOptions return body }, diff --git a/apps/sim/tools/typeform/create_form.ts b/apps/sim/tools/typeform/create_form.ts index 8e7da9defe..f3ba45ea4f 100644 --- a/apps/sim/tools/typeform/create_form.ts +++ b/apps/sim/tools/typeform/create_form.ts @@ -115,37 +115,13 @@ export const createFormTool: ToolConfig Date: Thu, 11 Dec 2025 21:12:23 -0800 Subject: [PATCH 11/34] feat(i18n): update translations (#2331) --- apps/docs/content/docs/de/tools/asana.mdx | 38 +++- .../docs/content/docs/de/tools/confluence.mdx | 37 +++- .../content/docs/de/tools/google_groups.mdx | 24 +-- .../content/docs/de/tools/google_vault.mdx | 30 +-- apps/docs/content/docs/de/tools/hubspot.mdx | 47 +++-- apps/docs/content/docs/de/tools/pipedrive.mdx | 94 ++++++---- apps/docs/content/docs/de/tools/sqs.mdx | 30 +-- apps/docs/content/docs/de/tools/typeform.mdx | 52 ++---- apps/docs/content/docs/es/tools/asana.mdx | 36 +++- .../docs/content/docs/es/tools/confluence.mdx | 47 ++++- .../content/docs/es/tools/google_groups.mdx | 24 +-- .../content/docs/es/tools/google_vault.mdx | 24 +-- apps/docs/content/docs/es/tools/hubspot.mdx | 43 +++-- apps/docs/content/docs/es/tools/pipedrive.mdx | 56 ++++-- apps/docs/content/docs/es/tools/sqs.mdx | 30 +-- apps/docs/content/docs/es/tools/typeform.mdx | 50 ++--- apps/docs/content/docs/fr/tools/asana.mdx | 38 +++- .../docs/content/docs/fr/tools/confluence.mdx | 27 +++ .../content/docs/fr/tools/google_groups.mdx | 24 +-- .../content/docs/fr/tools/google_vault.mdx | 24 +-- apps/docs/content/docs/fr/tools/hubspot.mdx | 51 +++-- apps/docs/content/docs/fr/tools/pipedrive.mdx | 58 ++++-- apps/docs/content/docs/fr/tools/sqs.mdx | 30 +-- apps/docs/content/docs/fr/tools/typeform.mdx | 50 ++--- apps/docs/content/docs/ja/tools/asana.mdx | 40 +++- .../docs/content/docs/ja/tools/confluence.mdx | 29 ++- .../content/docs/ja/tools/google_groups.mdx | 24 +-- .../content/docs/ja/tools/google_vault.mdx | 30 +-- apps/docs/content/docs/ja/tools/hubspot.mdx | 53 ++++-- apps/docs/content/docs/ja/tools/pipedrive.mdx | 58 ++++-- apps/docs/content/docs/ja/tools/sqs.mdx | 30 +-- apps/docs/content/docs/ja/tools/typeform.mdx | 54 ++---- apps/docs/content/docs/zh/tools/asana.mdx | 36 +++- .../docs/content/docs/zh/tools/confluence.mdx | 33 +++- .../content/docs/zh/tools/google_groups.mdx | 24 +-- .../content/docs/zh/tools/google_vault.mdx | 24 +-- apps/docs/content/docs/zh/tools/hubspot.mdx | 57 ++++-- apps/docs/content/docs/zh/tools/pipedrive.mdx | 56 ++++-- apps/docs/content/docs/zh/tools/sqs.mdx | 30 +-- apps/docs/content/docs/zh/tools/typeform.mdx | 54 ++---- apps/docs/i18n.lock | 174 +++++++++--------- 41 files changed, 1068 insertions(+), 702 deletions(-) diff --git a/apps/docs/content/docs/de/tools/asana.mdx b/apps/docs/content/docs/de/tools/asana.mdx index bc4843a1d9..a0f66ae3f2 100644 --- a/apps/docs/content/docs/de/tools/asana.mdx +++ b/apps/docs/content/docs/de/tools/asana.mdx @@ -34,7 +34,14 @@ Eine einzelne Aufgabe anhand der GID abrufen oder mehrere Aufgaben mit Filtern e | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Details einer einzelnen Aufgabe oder Array von Aufgaben, abhängig davon, ob taskGid angegeben wurde | +| `ts` | string | Zeitstempel der Antwort | +| `gid` | string | Global eindeutige Kennung der Aufgabe | +| `resource_type` | string | Ressourcentyp \(task\) | +| `resource_subtype` | string | Ressourcen-Subtyp | +| `name` | string | Aufgabenname | +| `notes` | string | Aufgabennotizen oder -beschreibung | +| `completed` | boolean | Ob die Aufgabe abgeschlossen ist | +| `assignee` | object | Details zum Zugewiesenen | ### `asana_create_task` @@ -54,8 +61,14 @@ Eine neue Aufgabe in Asana erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Status des Operationserfolgs | -| `output` | object | Details der erstellten Aufgabe mit Zeitstempel, GID, Name, Notizen und Permalink | +| `success` | boolean | Erfolgsstatus der Operation | +| `ts` | string | Zeitstempel der Antwort | +| `gid` | string | Global eindeutige Kennung der Aufgabe | +| `name` | string | Aufgabenname | +| `notes` | string | Aufgabennotizen oder -beschreibung | +| `completed` | boolean | Ob die Aufgabe abgeschlossen ist | +| `created_at` | string | Zeitstempel der Aufgabenerstellung | +| `permalink_url` | string | URL zur Aufgabe in Asana | ### `asana_update_task` @@ -77,7 +90,12 @@ Eine bestehende Aufgabe in Asana aktualisieren | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Aktualisierte Aufgabendetails mit Zeitstempel, GID, Name, Notizen und Änderungszeitstempel | +| `ts` | string | Zeitstempel der Antwort | +| `gid` | string | Global eindeutige Kennung der Aufgabe | +| `name` | string | Aufgabenname | +| `notes` | string | Aufgabennotizen oder -beschreibung | +| `completed` | boolean | Ob die Aufgabe abgeschlossen ist | +| `modified_at` | string | Zeitstempel der letzten Änderung der Aufgabe | ### `asana_get_projects` @@ -94,7 +112,8 @@ Alle Projekte aus einem Asana-Workspace abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Liste der Projekte mit ihrer GID, Name und Ressourcentyp | +| `ts` | string | Zeitstempel der Antwort | +| `projects` | array | Array von Projekten | ### `asana_search_tasks` @@ -115,7 +134,8 @@ Nach Aufgaben in einem Asana-Workspace suchen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Liste der Aufgaben, die den Suchkriterien entsprechen | +| `ts` | string | Zeitstempel der Antwort | +| `tasks` | array | Array von passenden Aufgaben | ### `asana_add_comment` @@ -133,7 +153,11 @@ Einen Kommentar (Story) zu einer Asana-Aufgabe hinzufügen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Kommentardetails einschließlich gid, Text, Erstellungszeitstempel und Autor | +| `ts` | string | Zeitstempel der Antwort | +| `gid` | string | Global eindeutige Kennung des Kommentars | +| `text` | string | Textinhalt des Kommentars | +| `created_at` | string | Erstellungszeitstempel des Kommentars | +| `created_by` | object | Details zum Autor des Kommentars | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/confluence.mdx b/apps/docs/content/docs/de/tools/confluence.mdx index 0c1768ab0c..3e16cfaec8 100644 --- a/apps/docs/content/docs/de/tools/confluence.mdx +++ b/apps/docs/content/docs/de/tools/confluence.mdx @@ -221,9 +221,36 @@ Löscht einen Kommentar von einer Confluence-Seite. | `commentId` | string | Gelöschte Kommentar-ID | | `deleted` | boolean | Löschstatus | +### `confluence_upload_attachment` + +Laden Sie eine Datei als Anhang zu einer Confluence-Seite hoch. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `domain` | string | Ja | Ihre Confluence-Domain (z.B. ihrfirma.atlassian.net) | +| `pageId` | string | Ja | Confluence-Seiten-ID, an die die Datei angehängt werden soll | +| `file` | file | Ja | Die als Anhang hochzuladende Datei | +| `fileName` | string | Nein | Optionaler benutzerdefinierter Dateiname für den Anhang | +| `comment` | string | Nein | Optionaler Kommentar zum Anhang | +| `cloudId` | string | Nein | Confluence Cloud-ID für die Instanz. Wenn nicht angegeben, wird sie über die Domain abgerufen. | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `ts` | string | Zeitstempel des Uploads | +| `attachmentId` | string | Hochgeladene Anhangs-ID | +| `title` | string | Dateiname des Anhangs | +| `fileSize` | number | Dateigröße in Bytes | +| `mediaType` | string | MIME-Typ des Anhangs | +| `downloadUrl` | string | Download-URL für den Anhang | +| `pageId` | string | Seiten-ID, zu der der Anhang hinzugefügt wurde | + ### `confluence_list_attachments` -Listet alle Anhänge einer Confluence-Seite auf. +Listen Sie alle Anhänge einer Confluence-Seite auf. #### Eingabe @@ -243,7 +270,7 @@ Listet alle Anhänge einer Confluence-Seite auf. ### `confluence_delete_attachment` -Löscht einen Anhang von einer Confluence-Seite (wird in den Papierkorb verschoben). +Löschen eines Anhangs von einer Confluence-Seite (wird in den Papierkorb verschoben). #### Eingabe @@ -263,7 +290,7 @@ Löscht einen Anhang von einer Confluence-Seite (wird in den Papierkorb verschob ### `confluence_list_labels` -Alle Labels einer Confluence-Seite auflisten. +Listet alle Labels einer Confluence-Seite auf. #### Eingabe @@ -282,7 +309,7 @@ Alle Labels einer Confluence-Seite auflisten. ### `confluence_get_space` -Details zu einem bestimmten Confluence-Space abrufen. +Ruft Details zu einem bestimmten Confluence-Space ab. #### Eingabe @@ -306,7 +333,7 @@ Details zu einem bestimmten Confluence-Space abrufen. ### `confluence_list_spaces` -Alle für den Benutzer zugänglichen Confluence-Spaces auflisten. +Listet alle Confluence-Spaces auf, auf die der Benutzer zugreifen kann. #### Eingabe diff --git a/apps/docs/content/docs/de/tools/google_groups.mdx b/apps/docs/content/docs/de/tools/google_groups.mdx index f9bdcb67ca..63575505b9 100644 --- a/apps/docs/content/docs/de/tools/google_groups.mdx +++ b/apps/docs/content/docs/de/tools/google_groups.mdx @@ -34,7 +34,8 @@ Alle Gruppen in einer Google Workspace-Domain auflisten | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `groups` | json | Array von Gruppenobjekten | +| `nextPageToken` | string | Token zum Abrufen der nächsten Ergebnisseite | ### `google_groups_get_group` @@ -50,7 +51,7 @@ Details einer bestimmten Google-Gruppe nach E-Mail oder Gruppen-ID abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `group` | json | Gruppenobjekt | ### `google_groups_create_group` @@ -68,7 +69,7 @@ Eine neue Google-Gruppe in der Domain erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `group` | json | Erstelltes Gruppenobjekt | ### `google_groups_update_group` @@ -87,7 +88,7 @@ Eine bestehende Google-Gruppe aktualisieren | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `group` | json | Aktualisiertes Gruppenobjekt | ### `google_groups_delete_group` @@ -103,7 +104,7 @@ Eine Google-Gruppe löschen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `message` | string | Erfolgsmeldung | ### `google_groups_list_members` @@ -122,7 +123,8 @@ Alle Mitglieder einer Google-Gruppe auflisten | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `members` | json | Array von Mitgliederobjekten | +| `nextPageToken` | string | Token zum Abrufen der nächsten Ergebnisseite | ### `google_groups_get_member` @@ -139,7 +141,7 @@ Details eines bestimmten Mitglieds in einer Google-Gruppe abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `member` | json | Mitgliederobjekt | ### `google_groups_add_member` @@ -157,7 +159,7 @@ Ein neues Mitglied zu einer Google-Gruppe hinzufügen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `member` | json | Hinzugefügtes Mitgliederobjekt | ### `google_groups_remove_member` @@ -174,7 +176,7 @@ Ein Mitglied aus einer Google-Gruppe entfernen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `message` | string | Erfolgsmeldung | ### `google_groups_update_member` @@ -192,7 +194,7 @@ Ein Mitglied aktualisieren | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `member` | json | Aktualisiertes Mitgliederobjekt | ### `google_groups_has_member` @@ -209,7 +211,7 @@ Prüfen, ob ein Benutzer Mitglied einer Google-Gruppe ist | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Google Groups API-Antwortdaten | +| `isMember` | boolean | Gibt an, ob der Benutzer ein Mitglied der Gruppe ist | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/google_vault.mdx b/apps/docs/content/docs/de/tools/google_vault.mdx index 100d5e1f91..910ad6a343 100644 --- a/apps/docs/content/docs/de/tools/google_vault.mdx +++ b/apps/docs/content/docs/de/tools/google_vault.mdx @@ -35,8 +35,7 @@ Einen Export in einer Angelegenheit erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `export` | json | Erstelltes Export-Objekt | ### `google_vault_list_matters_export` @@ -55,8 +54,9 @@ Exporte für eine Angelegenheit auflisten | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `exports` | json | Array von Export-Objekten | +| `export` | json | Einzelnes Export-Objekt \(wenn exportId angegeben ist\) | +| `nextPageToken` | string | Token zum Abrufen der nächsten Ergebnisseite | ### `google_vault_download_export_file` @@ -95,8 +95,7 @@ Eine Aufbewahrung in einer Angelegenheit erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault-API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `hold` | json | Erstelltes Hold-Objekt | ### `google_vault_list_matters_holds` @@ -113,10 +112,11 @@ Aufbewahrungen für eine Angelegenheit auflisten #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `holds` | json | Array von Hold-Objekten | +| `hold` | json | Einzelnes Hold-Objekt \(wenn holdId angegeben ist\) | +| `nextPageToken` | string | Token zum Abrufen der nächsten Ergebnisseite | ### `google_vault_create_matters` @@ -131,10 +131,9 @@ Einen neuen Fall in Google Vault erstellen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `matter` | json | Erstelltes Matter-Objekt | ### `google_vault_list_matters` @@ -150,10 +149,11 @@ Fälle auflisten oder einen bestimmten Fall abrufen, wenn matterId angegeben ist #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `output` | json | Vault API-Antwortdaten | -| `file` | json | Heruntergeladene Exportdatei \(UserFile\) aus Ausführungsdateien | +| `matters` | json | Array von Matter-Objekten | +| `matter` | json | Einzelnes Matter-Objekt \(wenn matterId angegeben ist\) | +| `nextPageToken` | string | Token zum Abrufen der nächsten Ergebnisseite | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/hubspot.mdx b/apps/docs/content/docs/de/tools/hubspot.mdx index 76ac4d98eb..a076a01d28 100644 --- a/apps/docs/content/docs/de/tools/hubspot.mdx +++ b/apps/docs/content/docs/de/tools/hubspot.mdx @@ -46,10 +46,11 @@ Alle Benutzer vom HubSpot-Konto abrufen #### Output -| Parameter | Type | Description | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Status des Operationserfolgs | -| `output` | object | Benutzerdaten | +| `users` | array | Array von HubSpot-Benutzerobjekten | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Erfolgsstatus der Operation | ### `hubspot_list_contacts` @@ -68,8 +69,10 @@ Alle Kontakte vom HubSpot-Konto mit Paginierungsunterstützung abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `contacts` | array | Array von HubSpot-Kontaktobjekten | +| `paging` | object | Paginierungsinformationen | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Kontaktdaten | ### `hubspot_get_contact` @@ -88,8 +91,9 @@ Einen einzelnen Kontakt anhand von ID oder E-Mail aus HubSpot abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `contact` | object | HubSpot-Kontaktobjekt mit Eigenschaften | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Kontaktdaten | ### `hubspot_create_contact` @@ -106,8 +110,9 @@ Erstellt einen neuen Kontakt in HubSpot. Erfordert mindestens eines der folgende | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `contact` | object | Erstelltes HubSpot-Kontaktobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Daten des erstellten Kontakts | ### `hubspot_update_contact` @@ -125,8 +130,9 @@ Aktualisiert einen bestehenden Kontakt in HubSpot anhand von ID oder E-Mail | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `contact` | object | Aktualisiertes HubSpot-Kontaktobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Daten des aktualisierten Kontakts | ### `hubspot_search_contacts` @@ -147,8 +153,11 @@ Suche nach Kontakten in HubSpot mit Filtern, Sortierung und Abfragen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `contacts` | array | Array übereinstimmender HubSpot-Kontaktobjekte | +| `total` | number | Gesamtanzahl übereinstimmender Kontakte | +| `paging` | object | Paginierungsinformationen | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Suchergebnisse | ### `hubspot_list_companies` @@ -167,8 +176,10 @@ Alle Unternehmen aus dem HubSpot-Konto mit Paginierungsunterstützung abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `companies` | array | Array von HubSpot-Unternehmensobjekten | +| `paging` | object | Paginierungsinformationen | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Unternehmensdaten | ### `hubspot_get_company` @@ -187,8 +198,9 @@ Ruft ein einzelnes Unternehmen anhand der ID oder Domain von HubSpot ab | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `company` | object | HubSpot-Unternehmensobjekt mit Eigenschaften | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Unternehmensdaten | ### `hubspot_create_company` @@ -205,8 +217,9 @@ Erstellt ein neues Unternehmen in HubSpot | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `company` | object | Erstelltes HubSpot-Unternehmensobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Daten des erstellten Unternehmens | ### `hubspot_update_company` @@ -224,8 +237,9 @@ Aktualisiert ein bestehendes Unternehmen in HubSpot anhand der ID oder Domain | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `company` | object | Aktualisiertes HubSpot-Unternehmensobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Aktualisierte Unternehmensdaten | ### `hubspot_search_companies` @@ -246,8 +260,11 @@ Suche nach Unternehmen in HubSpot mit Filtern, Sortierung und Abfragen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `companies` | array | Array übereinstimmender HubSpot-Unternehmensobjekte | +| `total` | number | Gesamtzahl übereinstimmender Unternehmen | +| `paging` | object | Paginierungsinformationen | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Suchergebnisse | ### `hubspot_list_deals` @@ -266,8 +283,10 @@ Alle Deals vom HubSpot-Konto mit Paginierungsunterstützung abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `deals` | array | Array von HubSpot-Deal-Objekten | +| `paging` | object | Paginierungsinformationen | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Deals-Daten | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/pipedrive.mdx b/apps/docs/content/docs/de/tools/pipedrive.mdx index 479d79bd45..bfa2cd9498 100644 --- a/apps/docs/content/docs/de/tools/pipedrive.mdx +++ b/apps/docs/content/docs/de/tools/pipedrive.mdx @@ -49,10 +49,11 @@ Alle Deals von Pipedrive mit optionalen Filtern abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `deals` | array | Array von Deal-Objekten aus Pipedrive | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Deals-Daten und Metadaten | ### `pipedrive_get_deal` @@ -66,10 +67,11 @@ Detaillierte Informationen über einen bestimmten Deal abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `deal` | object | Deal-Objekt mit vollständigen Details | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Deal-Details | ### `pipedrive_create_deal` @@ -93,8 +95,9 @@ Einen neuen Deal in Pipedrive erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `deal` | object | Das erstellte Deal-Objekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Details des erstellten Deals | ### `pipedrive_update_deal` @@ -115,8 +118,9 @@ Aktualisieren eines bestehenden Deals in Pipedrive | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `deal` | object | Das aktualisierte Deal-Objekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Details des aktualisierten Deals | ### `pipedrive_get_files` @@ -133,10 +137,11 @@ Dateien von Pipedrive mit optionalen Filtern abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Status des Operationserfolgs | -| `output` | object | Dateidaten | +| `files` | array | Array von Datei-Objekten aus Pipedrive | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Erfolgsstatus der Operation | ### `pipedrive_get_mail_messages` @@ -151,10 +156,11 @@ E-Mail-Threads aus dem Pipedrive-Postfach abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Status des Operationserfolgs | -| `output` | object | E-Mail-Thread-Daten | +| `messages` | array | Array von E-Mail-Thread-Objekten aus der Pipedrive-Mailbox | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Erfolgsstatus der Operation | ### `pipedrive_get_mail_thread` @@ -168,10 +174,11 @@ Alle Nachrichten aus einem bestimmten E-Mail-Thread abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `messages` | array | Array von E-Mail-Nachrichtenobjekten aus dem Thread | +| `metadata` | object | Operationsmetadaten einschließlich Thread-ID | | `success` | boolean | Status des Operationserfolgs | -| `output` | object | Nachrichtendaten des E-Mail-Threads | ### `pipedrive_get_pipelines` @@ -190,8 +197,9 @@ Alle Pipelines aus Pipedrive abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Pipeline-Daten | +| `pipelines` | array | Array von Pipeline-Objekten aus Pipedrive | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_get_pipeline_deals` @@ -210,8 +218,9 @@ Alle Deals in einer bestimmten Pipeline abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Pipeline-Deals-Daten | +| `deals` | array | Array von Deal-Objekten aus der Pipeline | +| `metadata` | object | Operationsmetadaten einschließlich Pipeline-ID | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_get_projects` @@ -229,8 +238,10 @@ Alle Projekte oder ein bestimmtes Projekt von Pipedrive abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Projektdaten oder Details eines einzelnen Projekts | +| `projects` | array | Array von Projektobjekten (bei Auflistung aller) | +| `project` | object | Einzelnes Projektobjekt (wenn project_id angegeben ist) | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_create_project` @@ -249,8 +260,9 @@ Erstelle ein neues Projekt in Pipedrive | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `project` | object | Das erstellte Projektobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Status des Operationserfolgs | -| `output` | object | Details des erstellten Projekts | ### `pipedrive_get_activities` @@ -271,8 +283,9 @@ Aktivitäten (Aufgaben) von Pipedrive mit optionalen Filtern abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `activities` | array | Array von Aktivitätsobjekten aus Pipedrive | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Status des Operationserfolgs | -| `output` | object | Aktivitätsdaten | ### `pipedrive_create_activity` @@ -296,8 +309,9 @@ Eine neue Aktivität (Aufgabe) in Pipedrive erstellen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | +| `activity` | object | Das erstellte Aktivitätsobjekt | +| `metadata` | object | Operationsmetadaten | | `success` | boolean | Status des Operationserfolgs | -| `output` | object | Details der erstellten Aktivität | ### `pipedrive_update_activity` @@ -317,10 +331,11 @@ Eine bestehende Aktivität (Aufgabe) in Pipedrive aktualisieren #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Aktualisierte Aktivitätsdetails | +| `activity` | object | Das aktualisierte Aktivitätsobjekt | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_get_leads` @@ -339,10 +354,12 @@ Alle Leads oder einen bestimmten Lead von Pipedrive abrufen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Lead-Daten oder Details eines einzelnen Leads | +| `leads` | array | Array von Lead-Objekten (bei Auflistung aller) | +| `lead` | object | Einzelnes Lead-Objekt (wenn lead_id angegeben ist) | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_create_lead` @@ -363,10 +380,11 @@ Einen neuen Lead in Pipedrive erstellen #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Details des erstellten Leads | +| `lead` | object | Das erstellte Lead-Objekt | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_update_lead` @@ -388,10 +406,11 @@ Einen vorhandenen Lead in Pipedrive aktualisieren #### Output -| Parameter | Type | Beschreibung | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Details des aktualisierten Leads | +| `lead` | object | Das aktualisierte Lead-Objekt | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ### `pipedrive_delete_lead` @@ -407,8 +426,9 @@ Einen bestimmten Lead aus Pipedrive löschen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `success` | boolean | Erfolgsstatus der Operation | -| `output` | object | Löschergebnis | +| `data` | object | Löschbestätigungsdaten | +| `metadata` | object | Operationsmetadaten | +| `success` | boolean | Status des Operationserfolgs | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/sqs.mdx b/apps/docs/content/docs/de/tools/sqs.mdx index 912f49ceb3..5c2b01782f 100644 --- a/apps/docs/content/docs/de/tools/sqs.mdx +++ b/apps/docs/content/docs/de/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: Verbindung zu Amazon SQS --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -40,22 +40,22 @@ Eine Nachricht an eine Amazon SQS-Warteschlange senden #### Eingabe -| Parameter | Typ | Erforderlich | Beschreibung | -| ------------------------ | ------ | ------------ | ---------------------------------------------------------------------------- | -| `region` | string | Ja | AWS-Region (z.B. us-east-1) | -| `accessKeyId` | string | Ja | AWS-Zugriffsschlüssel-ID | -| `secretAccessKey` | string | Ja | AWS-Geheimzugriffsschlüssel | -| `queueUrl` | string | Ja | Warteschlangen-URL (z.B. https://sqs.us-east-1.amazonaws.com/123456789012/my-queue) | -| `data` | object | Ja | Nachrichteninhalt als JSON-Objekt zu senden | -| `messageGroupId` | string | Nein | Nachrichtengruppen-ID (optional) | -| `messageDeduplicationId` | string | Nein | Nachrichten-Deduplizierungs-ID für FIFO-Warteschlangen (optional) | +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `region` | string | Ja | AWS-Region (z.B. us-east-1) | +| `accessKeyId` | string | Ja | AWS-Zugriffsschlüssel-ID | +| `secretAccessKey` | string | Ja | AWS-Geheimzugriffsschlüssel | +| `queueUrl` | string | Ja | Queue-URL | +| `data` | object | Ja | Zu sendender Nachrichtentext | +| `messageGroupId` | string | Nein | Nachrichtengruppen-ID (optional) | +| `messageDeduplicationId` | string | Nein | Nachrichtendeduplizierungs-ID (optional) | #### Ausgabe -| Parameter | Typ | Beschreibung | -| --------- | ------ | -------------------------------------------------------- | -| `message` | string | Erfolgs- oder Fehlermeldung, die das Ergebnis der Operation beschreibt | -| `id` | string | Nachrichten-ID | +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `message` | string | Statusmeldung der Operation | +| `id` | string | Nachrichten-ID | ## Hinweise diff --git a/apps/docs/content/docs/de/tools/typeform.mdx b/apps/docs/content/docs/de/tools/typeform.mdx index b923c41525..cc0b81877f 100644 --- a/apps/docs/content/docs/de/tools/typeform.mdx +++ b/apps/docs/content/docs/de/tools/typeform.mdx @@ -48,25 +48,9 @@ Formularantworten von Typeform abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `total_items` | number | Gesamtzahl der Antworten/Formulare | -| `page_count` | number | Gesamtseitenanzahl | -| `items` | json | Array der Antwort-/Formularelemente | -| `id` | string | Eindeutige Formular-ID | -| `title` | string | Formulartitel | -| `type` | string | Formulartyp | -| `created_at` | string | ISO-Zeitstempel der Formularerstellung | -| `last_updated_at` | string | ISO-Zeitstempel der letzten Aktualisierung | -| `settings` | json | Formulareinstellungsobjekt | -| `theme` | json | Theme-Konfigurationsobjekt | -| `workspace` | json | Workspace-Informationen | -| `fields` | json | Array der Formularfelder/Fragen | -| `thankyou_screens` | json | Array der Dankesbildschirme | -| `_links` | json | Links zu verwandten Ressourcen | -| `deleted` | boolean | Ob das Formular erfolgreich gelöscht wurde | -| `message` | string | Löschbestätigungsnachricht | -| `fileUrl` | string | URL der heruntergeladenen Datei | -| `contentType` | string | Datei-Content-Type | -| `filename` | string | Dateiname | +| `total_items` | number | Gesamtanzahl der Antworten | +| `page_count` | number | Gesamtanzahl der verfügbaren Seiten | +| `items` | array | Array von Antwortobjekten mit response_id, submitted_at, answers und metadata | ### `typeform_files` @@ -128,7 +112,7 @@ Eine Liste aller Formulare in Ihrem Typeform-Konto abrufen | --------- | ---- | ----------- | | `total_items` | number | Gesamtanzahl der Formulare im Konto | | `page_count` | number | Gesamtanzahl der verfügbaren Seiten | -| `items` | array | Array von Formularobjekten | +| `items` | array | Array von Formularobjekten mit id, title, created_at, last_updated_at, settings, theme und _links | ### `typeform_get_form` @@ -148,11 +132,13 @@ Vollständige Details und Struktur eines bestimmten Formulars abrufen | `id` | string | Eindeutige Formular-ID | | `title` | string | Formulartitel | | `type` | string | Formulartyp \(form, quiz, etc.\) | -| `created_at` | string | ISO-Zeitstempel der Formularerstellung | -| `last_updated_at` | string | ISO-Zeitstempel der letzten Aktualisierung | | `settings` | object | Formulareinstellungen einschließlich Sprache, Fortschrittsbalken, etc. | -| `theme` | object | Theme-Konfiguration mit Farben, Schriftarten und Design-Einstellungen | -| `workspace` | object | Workspace-Informationen | +| `theme` | object | Theme-Referenz | +| `workspace` | object | Workspace-Referenz | +| `fields` | array | Array von Formularfeldern/Fragen | +| `welcome_screens` | array | Array von Begrüßungsbildschirmen | +| `thankyou_screens` | array | Array von Dankesbildschirmen | +| `_links` | object | Links zu verwandten Ressourcen einschließlich öffentlicher Formular-URL | ### `typeform_create_form` @@ -177,13 +163,8 @@ Ein neues Formular mit Feldern und Einstellungen erstellen | `id` | string | Eindeutige Kennung des erstellten Formulars | | `title` | string | Formulartitel | | `type` | string | Formulartyp | -| `created_at` | string | ISO-Zeitstempel der Formularerstellung | -| `last_updated_at` | string | ISO-Zeitstempel der letzten Aktualisierung | -| `settings` | object | Formulareinstellungen | -| `theme` | object | Angewandte Theme-Konfiguration | -| `workspace` | object | Workspace-Informationen | | `fields` | array | Array der erstellten Formularfelder | -| `_links` | object | Links zu verwandten Ressourcen | +| `_links` | object | Links zu verwandten Ressourcen einschließlich öffentlicher Formular-URL | ### `typeform_update_form` @@ -204,13 +185,12 @@ Ein bestehendes Formular mit JSON Patch-Operationen aktualisieren | `id` | string | Eindeutige Kennung des aktualisierten Formulars | | `title` | string | Formulartitel | | `type` | string | Formulartyp | -| `created_at` | string | ISO-Zeitstempel der Formularerstellung | -| `last_updated_at` | string | ISO-Zeitstempel der letzten Aktualisierung | | `settings` | object | Formulareinstellungen | -| `theme` | object | Theme-Konfiguration | -| `workspace` | object | Workspace-Informationen | -| `fields` | array | Array der Formularfelder | -| `thankyou_screens` | array | Array der Dankesbildschirme | +| `theme` | object | Theme-Referenz | +| `workspace` | object | Workspace-Referenz | +| `fields` | array | Array von Formularfeldern | +| `welcome_screens` | array | Array von Begrüßungsbildschirmen | +| `thankyou_screens` | array | Array von Dankesbildschirmen | | `_links` | object | Links zu verwandten Ressourcen | ### `typeform_delete_form` diff --git a/apps/docs/content/docs/es/tools/asana.mdx b/apps/docs/content/docs/es/tools/asana.mdx index ce12a8ea99..908d4c2d4b 100644 --- a/apps/docs/content/docs/es/tools/asana.mdx +++ b/apps/docs/content/docs/es/tools/asana.mdx @@ -34,7 +34,14 @@ Recupera una tarea individual por GID u obtén múltiples tareas con filtros | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles de una tarea individual o matriz de tareas, dependiendo de si se proporcionó taskGid | +| `ts` | string | Marca de tiempo de la respuesta | +| `gid` | string | Identificador único global de la tarea | +| `resource_type` | string | Tipo de recurso \(tarea\) | +| `resource_subtype` | string | Subtipo de recurso | +| `name` | string | Nombre de la tarea | +| `notes` | string | Notas o descripción de la tarea | +| `completed` | boolean | Si la tarea está completada | +| `assignee` | object | Detalles del asignado | ### `asana_create_task` @@ -55,7 +62,13 @@ Crear una nueva tarea en Asana | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles de la tarea creada con marca de tiempo, gid, nombre, notas y enlace permanente | +| `ts` | string | Marca de tiempo de la respuesta | +| `gid` | string | Identificador único global de la tarea | +| `name` | string | Nombre de la tarea | +| `notes` | string | Notas o descripción de la tarea | +| `completed` | boolean | Si la tarea está completada | +| `created_at` | string | Marca de tiempo de creación de la tarea | +| `permalink_url` | string | URL a la tarea en Asana | ### `asana_update_task` @@ -77,7 +90,12 @@ Actualizar una tarea existente en Asana | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles actualizados de la tarea con marca de tiempo, gid, nombre, notas y marca de tiempo de modificación | +| `ts` | string | Marca de tiempo de la respuesta | +| `gid` | string | Identificador único global de la tarea | +| `name` | string | Nombre de la tarea | +| `notes` | string | Notas o descripción de la tarea | +| `completed` | boolean | Si la tarea está completada | +| `modified_at` | string | Marca de tiempo de última modificación de la tarea | ### `asana_get_projects` @@ -94,7 +112,8 @@ Recuperar todos los proyectos de un espacio de trabajo de Asana | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Lista de proyectos con su gid, nombre y tipo de recurso | +| `ts` | string | Marca de tiempo de la respuesta | +| `projects` | array | Array de proyectos | ### `asana_search_tasks` @@ -115,7 +134,8 @@ Buscar tareas en un espacio de trabajo de Asana | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Lista de tareas que coinciden con los criterios de búsqueda | +| `ts` | string | Marca de tiempo de la respuesta | +| `tasks` | array | Array de tareas coincidentes | ### `asana_add_comment` @@ -133,7 +153,11 @@ Añadir un comentario (historia) a una tarea de Asana | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del comentario incluyendo gid, texto, marca de tiempo de creación y autor | +| `ts` | string | Marca de tiempo de la respuesta | +| `gid` | string | Identificador único global del comentario | +| `text` | string | Contenido de texto del comentario | +| `created_at` | string | Marca de tiempo de creación del comentario | +| `created_by` | object | Detalles del autor del comentario | ## Notas diff --git a/apps/docs/content/docs/es/tools/confluence.mdx b/apps/docs/content/docs/es/tools/confluence.mdx index f1d1cd6e43..6af60fdd60 100644 --- a/apps/docs/content/docs/es/tools/confluence.mdx +++ b/apps/docs/content/docs/es/tools/confluence.mdx @@ -221,17 +221,44 @@ Eliminar un comentario de una página de Confluence. | `commentId` | string | ID del comentario eliminado | | `deleted` | boolean | Estado de eliminación | +### `confluence_upload_attachment` + +Sube un archivo como adjunto a una página de Confluence. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `domain` | string | Sí | Tu dominio de Confluence \(p. ej., tuempresa.atlassian.net\) | +| `pageId` | string | Sí | ID de la página de Confluence a la que adjuntar el archivo | +| `file` | file | Sí | El archivo a subir como adjunto | +| `fileName` | string | No | Nombre de archivo personalizado opcional para el adjunto | +| `comment` | string | No | Comentario opcional para añadir al adjunto | +| `cloudId` | string | No | ID de Confluence Cloud para la instancia. Si no se proporciona, se obtendrá utilizando el dominio. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `ts` | string | Marca de tiempo de la subida | +| `attachmentId` | string | ID del adjunto subido | +| `title` | string | Nombre del archivo adjunto | +| `fileSize` | number | Tamaño del archivo en bytes | +| `mediaType` | string | Tipo MIME del adjunto | +| `downloadUrl` | string | URL de descarga del adjunto | +| `pageId` | string | ID de la página a la que se añadió el adjunto | + ### `confluence_list_attachments` -Listar todos los archivos adjuntos en una página de Confluence. +Lista todos los adjuntos en una página de Confluence. #### Entrada | Parámetro | Tipo | Obligatorio | Descripción | | --------- | ---- | -------- | ----------- | | `domain` | string | Sí | Tu dominio de Confluence \(p. ej., tuempresa.atlassian.net\) | -| `pageId` | string | Sí | ID de la página de Confluence de la que listar los archivos adjuntos | -| `limit` | number | No | Número máximo de archivos adjuntos a devolver \(predeterminado: 25\) | +| `pageId` | string | Sí | ID de la página de Confluence de la que listar adjuntos | +| `limit` | number | No | Número máximo de adjuntos a devolver \(predeterminado: 25\) | | `cloudId` | string | No | ID de Confluence Cloud para la instancia. Si no se proporciona, se obtendrá utilizando el dominio. | #### Salida @@ -239,31 +266,31 @@ Listar todos los archivos adjuntos en una página de Confluence. | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `ts` | string | Marca de tiempo de la recuperación | -| `attachments` | array | Lista de adjuntos | +| `attachments` | array | Lista de archivos adjuntos | ### `confluence_delete_attachment` -Eliminar un adjunto de una página de Confluence (se mueve a la papelera). +Eliminar un archivo adjunto de una página de Confluence (lo mueve a la papelera). #### Entrada | Parámetro | Tipo | Obligatorio | Descripción | | --------- | ---- | -------- | ----------- | | `domain` | string | Sí | Tu dominio de Confluence \(p. ej., tuempresa.atlassian.net\) | -| `attachmentId` | string | Sí | ID del adjunto de Confluence a eliminar | +| `attachmentId` | string | Sí | ID del archivo adjunto de Confluence a eliminar | | `cloudId` | string | No | ID de Confluence Cloud para la instancia. Si no se proporciona, se obtendrá utilizando el dominio. | #### Salida | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `ts` | string | Marca de tiempo de la eliminación | -| `attachmentId` | string | ID del adjunto eliminado | -| `deleted` | boolean | Estado de la eliminación | +| `ts` | string | Marca de tiempo de eliminación | +| `attachmentId` | string | ID del archivo adjunto eliminado | +| `deleted` | boolean | Estado de eliminación | ### `confluence_list_labels` -Listar todas las etiquetas en una página de Confluence. +Listar todas las etiquetas de una página de Confluence. #### Entrada diff --git a/apps/docs/content/docs/es/tools/google_groups.mdx b/apps/docs/content/docs/es/tools/google_groups.mdx index 174b057017..3b8cce9749 100644 --- a/apps/docs/content/docs/es/tools/google_groups.mdx +++ b/apps/docs/content/docs/es/tools/google_groups.mdx @@ -34,7 +34,8 @@ Listar todos los grupos en un dominio de Google Workspace | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `groups` | json | Array de objetos de grupo | +| `nextPageToken` | string | Token para obtener la siguiente página de resultados | ### `google_groups_get_group` @@ -50,7 +51,7 @@ Obtener detalles de un Grupo de Google específico por correo electrónico o ID | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `group` | json | Objeto de grupo | ### `google_groups_create_group` @@ -68,7 +69,7 @@ Crear un nuevo Grupo de Google en el dominio | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `group` | json | Objeto de grupo creado | ### `google_groups_update_group` @@ -87,7 +88,7 @@ Actualizar un grupo de Google existente | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `group` | json | Objeto de grupo actualizado | ### `google_groups_delete_group` @@ -103,7 +104,7 @@ Eliminar un grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `message` | string | Mensaje de éxito | ### `google_groups_list_members` @@ -122,7 +123,8 @@ Listar todos los miembros de un Grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Grupos de Google | +| `members` | json | Array de objetos de miembro | +| `nextPageToken` | string | Token para obtener la siguiente página de resultados | ### `google_groups_get_member` @@ -139,7 +141,7 @@ Obtener detalles de un miembro específico en un Grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Grupos de Google | +| `member` | json | Objeto de miembro | ### `google_groups_add_member` @@ -157,7 +159,7 @@ Añadir un nuevo miembro a un Grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `member` | json | Objeto de miembro añadido | ### `google_groups_remove_member` @@ -174,7 +176,7 @@ Eliminar un miembro de un grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `message` | string | Mensaje de éxito | ### `google_groups_update_member` @@ -192,7 +194,7 @@ Actualizar un miembro | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `member` | json | Objeto de miembro actualizado | ### `google_groups_has_member` @@ -209,7 +211,7 @@ Comprobar si un usuario es miembro de un grupo de Google | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Google Groups | +| `isMember` | boolean | Indica si el usuario es miembro del grupo | ## Notas diff --git a/apps/docs/content/docs/es/tools/google_vault.mdx b/apps/docs/content/docs/es/tools/google_vault.mdx index f5fccbca7e..69d0068fe4 100644 --- a/apps/docs/content/docs/es/tools/google_vault.mdx +++ b/apps/docs/content/docs/es/tools/google_vault.mdx @@ -34,8 +34,7 @@ Crear una exportación en un asunto | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado \(UserFile\) de los archivos de ejecución | +| `export` | json | Objeto de exportación creado | ### `google_vault_list_matters_export` @@ -54,8 +53,9 @@ Listar exportaciones para un asunto | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado \(UserFile\) de los archivos de ejecución | +| `exports` | json | Array de objetos de exportación | +| `export` | json | Objeto de exportación único \(cuando se proporciona exportId\) | +| `nextPageToken` | string | Token para obtener la siguiente página de resultados | ### `google_vault_download_export_file` @@ -94,8 +94,7 @@ Crear una retención en un asunto | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado \(UserFile\) de los archivos de ejecución | +| `hold` | json | Objeto de retención creado | ### `google_vault_list_matters_holds` @@ -114,8 +113,9 @@ Listar retenciones para un asunto | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado (UserFile) de los archivos de ejecución | +| `holds` | json | Array de objetos de retención | +| `hold` | json | Objeto de retención único \(cuando se proporciona holdId\) | +| `nextPageToken` | string | Token para obtener la siguiente página de resultados | ### `google_vault_create_matters` @@ -132,8 +132,7 @@ Crear un nuevo asunto en Google Vault | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado (UserFile) de los archivos de ejecución | +| `matter` | json | Objeto de asunto creado | ### `google_vault_list_matters` @@ -151,8 +150,9 @@ Listar asuntos, o obtener un asunto específico si se proporciona matterId | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `output` | json | Datos de respuesta de la API de Vault | -| `file` | json | Archivo de exportación descargado (UserFile) de los archivos de ejecución | +| `matters` | json | Array de objetos de asunto | +| `matter` | json | Objeto de asunto único \(cuando se proporciona matterId\) | +| `nextPageToken` | string | Token para obtener la siguiente página de resultados | ## Notas diff --git a/apps/docs/content/docs/es/tools/hubspot.mdx b/apps/docs/content/docs/es/tools/hubspot.mdx index 59823cd342..eb74136eb1 100644 --- a/apps/docs/content/docs/es/tools/hubspot.mdx +++ b/apps/docs/content/docs/es/tools/hubspot.mdx @@ -47,8 +47,9 @@ Recuperar todos los usuarios de la cuenta de HubSpot | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `users` | array | Array de objetos de usuario de HubSpot | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de usuarios | ### `hubspot_list_contacts` @@ -67,8 +68,10 @@ Recuperar todos los contactos de la cuenta de HubSpot con soporte de paginación | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `contacts` | array | Array de objetos de contacto de HubSpot | +| `paging` | object | Información de paginación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de contactos | ### `hubspot_get_contact` @@ -87,8 +90,9 @@ Recuperar un solo contacto por ID o email desde HubSpot | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `contact` | object | Objeto de contacto de HubSpot con propiedades | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos del contacto | ### `hubspot_create_contact` @@ -105,8 +109,9 @@ Crear un nuevo contacto en HubSpot. Requiere al menos uno de: email, firstname o | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `contact` | object | Objeto de contacto de HubSpot creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | objeto | Datos del contacto creado | ### `hubspot_update_contact` @@ -124,8 +129,9 @@ Actualizar un contacto existente en HubSpot por ID o email | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `contact` | object | Objeto de contacto de HubSpot actualizado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | objeto | Datos del contacto actualizado | ### `hubspot_search_contacts` @@ -146,8 +152,11 @@ Buscar contactos en HubSpot usando filtros, ordenación y consultas | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `contacts` | array | Array de objetos de contacto de HubSpot coincidentes | +| `total` | number | Número total de contactos coincidentes | +| `paging` | object | Información de paginación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Resultados de la búsqueda | ### `hubspot_list_companies` @@ -166,8 +175,10 @@ Recuperar todas las empresas de la cuenta de HubSpot con soporte de paginación | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `companies` | array | Array de objetos de empresa de HubSpot | +| `paging` | object | Información de paginación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de las empresas | ### `hubspot_get_company` @@ -186,8 +197,9 @@ Recuperar una sola empresa por ID o dominio desde HubSpot | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `company` | object | Objeto de empresa de HubSpot con propiedades | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de la empresa | ### `hubspot_create_company` @@ -204,8 +216,9 @@ Crear una nueva empresa en HubSpot | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `company` | object | Objeto de empresa de HubSpot creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de la empresa creada | ### `hubspot_update_company` @@ -223,8 +236,9 @@ Actualizar una empresa existente en HubSpot por ID o dominio | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `company` | object | Objeto de empresa de HubSpot actualizado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos actualizados de la empresa | ### `hubspot_search_companies` @@ -245,8 +259,11 @@ Buscar empresas en HubSpot usando filtros, ordenación y consultas | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `companies` | array | Array de objetos de empresa de HubSpot coincidentes | +| `total` | number | Número total de empresas coincidentes | +| `paging` | object | Información de paginación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Resultados de la búsqueda | ### `hubspot_list_deals` @@ -265,8 +282,10 @@ Recuperar todos los acuerdos de la cuenta de HubSpot con soporte de paginación | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deals` | array | Array de objetos de negocio de HubSpot | +| `paging` | object | Información de paginación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de ofertas | ## Notas diff --git a/apps/docs/content/docs/es/tools/pipedrive.mdx b/apps/docs/content/docs/es/tools/pipedrive.mdx index 2bf2798f97..1a20d1969c 100644 --- a/apps/docs/content/docs/es/tools/pipedrive.mdx +++ b/apps/docs/content/docs/es/tools/pipedrive.mdx @@ -51,8 +51,9 @@ Recupera todos los acuerdos de Pipedrive con filtros opcionales | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deals` | array | Array de objetos de acuerdos de Pipedrive | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos y metadatos de los acuerdos | ### `pipedrive_get_deal` @@ -68,8 +69,9 @@ Recuperar información detallada sobre un acuerdo específico | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deal` | object | Objeto de acuerdo con detalles completos | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del acuerdo | ### `pipedrive_create_deal` @@ -93,8 +95,9 @@ Crear un nuevo acuerdo en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deal` | object | El objeto de acuerdo creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del acuerdo creado | ### `pipedrive_update_deal` @@ -115,8 +118,9 @@ Actualizar un acuerdo existente en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deal` | object | El objeto de acuerdo actualizado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del acuerdo actualizado | ### `pipedrive_get_files` @@ -135,8 +139,9 @@ Recuperar archivos de Pipedrive con filtros opcionales | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `files` | array | Array de objetos de archivo de Pipedrive | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de archivos | ### `pipedrive_get_mail_messages` @@ -153,8 +158,9 @@ Recuperar hilos de correo del buzón de Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `messages` | array | Array de objetos de hilos de correo del buzón de Pipedrive | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de hilos de correo | ### `pipedrive_get_mail_thread` @@ -170,8 +176,9 @@ Recuperar todos los mensajes de un hilo de correo específico | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `messages` | array | Array de objetos de mensajes de correo del hilo | +| `metadata` | object | Metadatos de la operación incluyendo ID del hilo | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de mensajes del hilo de correo | ### `pipedrive_get_pipelines` @@ -190,8 +197,9 @@ Recuperar todos los pipelines de Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `pipelines` | array | Array de objetos de pipeline de Pipedrive | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de los pipelines | ### `pipedrive_get_pipeline_deals` @@ -210,8 +218,9 @@ Recuperar todos los acuerdos en un pipeline específico | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `deals` | array | Array de objetos de acuerdos del pipeline | +| `metadata` | object | Metadatos de la operación incluyendo ID del pipeline | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de acuerdos del pipeline | ### `pipedrive_get_projects` @@ -229,8 +238,10 @@ Recuperar todos los proyectos o un proyecto específico de Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `projects` | array | Array de objetos de proyectos \(al listar todos\) | +| `project` | object | Objeto de un solo proyecto \(cuando se proporciona project_id\) | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de proyectos o detalles de un solo proyecto | ### `pipedrive_create_project` @@ -249,8 +260,9 @@ Crear un nuevo proyecto en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `project` | object | El objeto del proyecto creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del proyecto creado | ### `pipedrive_get_activities` @@ -271,8 +283,9 @@ Recuperar actividades (tareas) de Pipedrive con filtros opcionales | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `activities` | array | Array de objetos de actividades de Pipedrive | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de actividades | ### `pipedrive_create_activity` @@ -296,8 +309,9 @@ Crear una nueva actividad (tarea) en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `activity` | object | El objeto de actividad creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles de la actividad creada | ### `pipedrive_update_activity` @@ -319,8 +333,9 @@ Actualizar una actividad existente (tarea) en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `activity` | object | El objeto de actividad actualizado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles de la actividad actualizada | ### `pipedrive_get_leads` @@ -341,8 +356,10 @@ Recuperar todos los leads o un lead específico de Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `leads` | array | Array de objetos de leads \(al listar todos\) | +| `lead` | object | Objeto de lead individual \(cuando se proporciona lead_id\) | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Datos de leads o detalles de un solo lead | ### `pipedrive_create_lead` @@ -365,8 +382,9 @@ Crear un nuevo lead en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `lead` | object | El objeto de lead creado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del lead creado | ### `pipedrive_update_lead` @@ -390,8 +408,9 @@ Actualizar un lead existente en Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `lead` | object | El objeto de lead actualizado | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Detalles del lead actualizado | ### `pipedrive_delete_lead` @@ -407,8 +426,9 @@ Eliminar un lead específico de Pipedrive | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | +| `data` | object | Datos de confirmación de eliminación | +| `metadata` | object | Metadatos de la operación | | `success` | boolean | Estado de éxito de la operación | -| `output` | object | Resultado de la eliminación | ## Notas diff --git a/apps/docs/content/docs/es/tools/sqs.mdx b/apps/docs/content/docs/es/tools/sqs.mdx index cfe1dd8368..d4832cd2f5 100644 --- a/apps/docs/content/docs/es/tools/sqs.mdx +++ b/apps/docs/content/docs/es/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: Conectar a Amazon SQS --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -40,22 +40,22 @@ Enviar un mensaje a una cola de Amazon SQS #### Entrada -| Parámetro | Tipo | Requerido | Descripción | -| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | -| `region` | string | Sí | Región de AWS \(p. ej., us-east-1\) | -| `accessKeyId` | string | Sí | ID de clave de acceso de AWS | -| `secretAccessKey` | string | Sí | Clave de acceso secreta de AWS | -| `queueUrl` | string | Sí | URL de la cola \(p. ej., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | -| `data` | object | Sí | Cuerpo del mensaje para enviar como objeto JSON | -| `messageGroupId` | string | No | ID de grupo de mensajes \(opcional\) | -| `messageDeduplicationId` | string | No | ID de deduplicación de mensajes para colas FIFO \(opcional\) | +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `region` | string | Sí | Región de AWS (p. ej., us-east-1) | +| `accessKeyId` | string | Sí | ID de clave de acceso de AWS | +| `secretAccessKey` | string | Sí | Clave de acceso secreta de AWS | +| `queueUrl` | string | Sí | URL de la cola | +| `data` | object | Sí | Cuerpo del mensaje a enviar | +| `messageGroupId` | string | No | ID del grupo de mensajes (opcional) | +| `messageDeduplicationId` | string | No | ID de deduplicación del mensaje (opcional) | #### Salida -| Parámetro | Tipo | Descripción | -| --------- | ------ | --------------------------------------------------------- | -| `message` | string | Mensaje de éxito o error que describe el resultado de la operación | -| `id` | string | ID del mensaje | +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `message` | string | Mensaje de estado de la operación | +| `id` | string | ID del mensaje | ## Notas diff --git a/apps/docs/content/docs/es/tools/typeform.mdx b/apps/docs/content/docs/es/tools/typeform.mdx index f6bb609dc0..33a925e155 100644 --- a/apps/docs/content/docs/es/tools/typeform.mdx +++ b/apps/docs/content/docs/es/tools/typeform.mdx @@ -48,25 +48,9 @@ Recuperar respuestas de formularios de Typeform | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `total_items` | number | Recuento total de respuestas/formularios | -| `page_count` | number | Recuento total de páginas | -| `items` | json | Array de elementos de respuesta/formulario | -| `id` | string | Identificador único del formulario | -| `title` | string | Título del formulario | -| `type` | string | Tipo de formulario | -| `created_at` | string | Marca de tiempo ISO de creación del formulario | -| `last_updated_at` | string | Marca de tiempo ISO de última actualización | -| `settings` | json | Objeto de configuración del formulario | -| `theme` | json | Objeto de configuración del tema | -| `workspace` | json | Información del espacio de trabajo | -| `fields` | json | Array de campos/preguntas del formulario | -| `thankyou_screens` | json | Array de pantallas de agradecimiento | -| `_links` | json | Enlaces a recursos relacionados | -| `deleted` | boolean | Si el formulario se eliminó correctamente | -| `message` | string | Mensaje de confirmación de eliminación | -| `fileUrl` | string | URL del archivo descargado | -| `contentType` | string | Tipo de contenido del archivo | -| `filename` | string | Nombre del archivo | +| `total_items` | number | Número total de respuestas | +| `page_count` | number | Número total de páginas disponibles | +| `items` | array | Array de objetos de respuesta con response_id, submitted_at, answers y metadata | ### `typeform_files` @@ -128,7 +112,7 @@ Recupera una lista de todos los formularios en tu cuenta de Typeform | --------- | ---- | ----------- | | `total_items` | number | Número total de formularios en la cuenta | | `page_count` | number | Número total de páginas disponibles | -| `items` | array | Array de objetos de formulario | +| `items` | array | Array de objetos de formulario con id, title, created_at, last_updated_at, settings, theme y _links | ### `typeform_get_form` @@ -148,11 +132,13 @@ Recuperar detalles completos y estructura de un formulario específico | `id` | string | Identificador único del formulario | | `title` | string | Título del formulario | | `type` | string | Tipo de formulario \(form, quiz, etc.\) | -| `created_at` | string | Marca de tiempo ISO de creación del formulario | -| `last_updated_at` | string | Marca de tiempo ISO de última actualización | | `settings` | object | Configuración del formulario incluyendo idioma, barra de progreso, etc. | -| `theme` | object | Configuración del tema con colores, fuentes y ajustes de diseño | -| `workspace` | object | Información del espacio de trabajo | +| `theme` | object | Referencia del tema | +| `workspace` | object | Referencia del espacio de trabajo | +| `fields` | array | Array de campos/preguntas del formulario | +| `welcome_screens` | array | Array de pantallas de bienvenida | +| `thankyou_screens` | array | Array de pantallas de agradecimiento | +| `_links` | object | Enlaces a recursos relacionados incluyendo URL pública del formulario | ### `typeform_create_form` @@ -177,13 +163,8 @@ Crear un nuevo formulario con campos y configuraciones | `id` | string | Identificador único del formulario creado | | `title` | string | Título del formulario | | `type` | string | Tipo de formulario | -| `created_at` | string | Marca de tiempo ISO de creación del formulario | -| `last_updated_at` | string | Marca de tiempo ISO de última actualización | -| `settings` | object | Configuración del formulario | -| `theme` | object | Configuración del tema aplicado | -| `workspace` | object | Información del espacio de trabajo | -| `fields` | array | Array de campos del formulario creados | -| `_links` | object | Enlaces a recursos relacionados | +| `fields` | array | Array de campos del formulario creado | +| `_links` | object | Enlaces a recursos relacionados incluyendo URL pública del formulario | ### `typeform_update_form` @@ -204,12 +185,11 @@ Actualizar un formulario existente usando operaciones JSON Patch | `id` | string | Identificador único del formulario actualizado | | `title` | string | Título del formulario | | `type` | string | Tipo de formulario | -| `created_at` | string | Marca de tiempo ISO de creación del formulario | -| `last_updated_at` | string | Marca de tiempo ISO de última actualización | | `settings` | object | Configuración del formulario | -| `theme` | object | Configuración del tema | -| `workspace` | object | Información del espacio de trabajo | +| `theme` | object | Referencia del tema | +| `workspace` | object | Referencia del espacio de trabajo | | `fields` | array | Array de campos del formulario | +| `welcome_screens` | array | Array de pantallas de bienvenida | | `thankyou_screens` | array | Array de pantallas de agradecimiento | | `_links` | object | Enlaces a recursos relacionados | diff --git a/apps/docs/content/docs/fr/tools/asana.mdx b/apps/docs/content/docs/fr/tools/asana.mdx index 75b3acbb47..0636be5567 100644 --- a/apps/docs/content/docs/fr/tools/asana.mdx +++ b/apps/docs/content/docs/fr/tools/asana.mdx @@ -34,7 +34,14 @@ Récupérer une tâche unique par GID ou obtenir plusieurs tâches avec des filt | Paramètre | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails d'une tâche unique ou tableau de tâches, selon que taskGid a été fourni ou non | +| `ts` | string | Horodatage de la réponse | +| `gid` | string | Identifiant unique global de la tâche | +| `resource_type` | string | Type de ressource \(tâche\) | +| `resource_subtype` | string | Sous-type de ressource | +| `name` | string | Nom de la tâche | +| `notes` | string | Notes ou description de la tâche | +| `completed` | boolean | Si la tâche est terminée | +| `assignee` | object | Détails de l'assigné | ### `asana_create_task` @@ -54,8 +61,14 @@ Créer une nouvelle tâche dans Asana | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Détails de la tâche créée avec horodatage, gid, nom, notes et lien permanent | +| `success` | boolean | Statut de réussite de l'opération | +| `ts` | string | Horodatage de la réponse | +| `gid` | string | Identifiant unique global de la tâche | +| `name` | string | Nom de la tâche | +| `notes` | string | Notes ou description de la tâche | +| `completed` | boolean | Si la tâche est terminée | +| `created_at` | string | Horodatage de création de la tâche | +| `permalink_url` | string | URL vers la tâche dans Asana | ### `asana_update_task` @@ -77,7 +90,12 @@ Mettre à jour une tâche existante dans Asana | Paramètre | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails de la tâche mise à jour avec horodatage, gid, nom, notes et horodatage de modification | +| `ts` | string | Horodatage de la réponse | +| `gid` | string | Identifiant unique global de la tâche | +| `name` | string | Nom de la tâche | +| `notes` | string | Notes ou description de la tâche | +| `completed` | boolean | Si la tâche est terminée | +| `modified_at` | string | Horodatage de dernière modification de la tâche | ### `asana_get_projects` @@ -94,7 +112,8 @@ Récupérer tous les projets d'un espace de travail Asana | Paramètre | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Liste des projets avec leur gid, nom et type de ressource | +| `ts` | string | Horodatage de la réponse | +| `projects` | array | Tableau de projets | ### `asana_search_tasks` @@ -115,7 +134,8 @@ Rechercher des tâches dans un espace de travail Asana | Paramètre | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Liste des tâches correspondant aux critères de recherche | +| `ts` | string | Horodatage de la réponse | +| `tasks` | array | Tableau des tâches correspondantes | ### `asana_add_comment` @@ -133,7 +153,11 @@ Ajouter un commentaire (story) à une tâche Asana | Paramètre | Type | Description | | --------- | ---- | ----------- | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails du commentaire incluant gid, texte, horodatage de création et auteur | +| `ts` | string | Horodatage de la réponse | +| `gid` | string | Identifiant unique global du commentaire | +| `text` | string | Contenu textuel du commentaire | +| `created_at` | string | Horodatage de création du commentaire | +| `created_by` | object | Détails de l'auteur du commentaire | ## Notes diff --git a/apps/docs/content/docs/fr/tools/confluence.mdx b/apps/docs/content/docs/fr/tools/confluence.mdx index cec81c263a..822ddceaa4 100644 --- a/apps/docs/content/docs/fr/tools/confluence.mdx +++ b/apps/docs/content/docs/fr/tools/confluence.mdx @@ -221,6 +221,33 @@ Supprimer un commentaire d'une page Confluence. | `commentId` | chaîne | ID du commentaire supprimé | | `deleted` | booléen | Statut de la suppression | +### `confluence_upload_attachment` + +Téléverser un fichier en tant que pièce jointe à une page Confluence. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `domain` | chaîne | Oui | Votre domaine Confluence \(ex. : votreentreprise.atlassian.net\) | +| `pageId` | chaîne | Oui | ID de la page Confluence à laquelle joindre le fichier | +| `file` | fichier | Oui | Le fichier à téléverser en tant que pièce jointe | +| `fileName` | chaîne | Non | Nom de fichier personnalisé optionnel pour la pièce jointe | +| `comment` | chaîne | Non | Commentaire optionnel à ajouter à la pièce jointe | +| `cloudId` | chaîne | Non | ID Cloud Confluence pour l'instance. S'il n'est pas fourni, il sera récupéré à l'aide du domaine. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `ts` | chaîne | Horodatage du téléversement | +| `attachmentId` | chaîne | ID de la pièce jointe téléversée | +| `title` | chaîne | Nom du fichier de la pièce jointe | +| `fileSize` | nombre | Taille du fichier en octets | +| `mediaType` | chaîne | Type MIME de la pièce jointe | +| `downloadUrl` | chaîne | URL de téléchargement de la pièce jointe | +| `pageId` | chaîne | ID de la page à laquelle la pièce jointe a été ajoutée | + ### `confluence_list_attachments` Lister toutes les pièces jointes d'une page Confluence. diff --git a/apps/docs/content/docs/fr/tools/google_groups.mdx b/apps/docs/content/docs/fr/tools/google_groups.mdx index 837c112551..705ca67b43 100644 --- a/apps/docs/content/docs/fr/tools/google_groups.mdx +++ b/apps/docs/content/docs/fr/tools/google_groups.mdx @@ -34,7 +34,8 @@ Lister tous les groupes dans un domaine Google Workspace | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `groups` | json | Tableau d'objets de groupe | +| `nextPageToken` | string | Jeton pour récupérer la page suivante de résultats | ### `google_groups_get_group` @@ -50,7 +51,7 @@ Obtenir les détails d'un groupe Google spécifique par email ou ID de groupe | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `group` | json | Objet de groupe | ### `google_groups_create_group` @@ -68,7 +69,7 @@ Créer un nouveau groupe Google dans le domaine | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `group` | json | Objet de groupe créé | ### `google_groups_update_group` @@ -87,7 +88,7 @@ Mettre à jour un groupe Google existant | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `group` | json | Objet de groupe mis à jour | ### `google_groups_delete_group` @@ -103,7 +104,7 @@ Supprimer un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `message` | string | Message de succès | ### `google_groups_list_members` @@ -122,7 +123,8 @@ Lister tous les membres d'un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `members` | json | Tableau d'objets de membre | +| `nextPageToken` | string | Jeton pour récupérer la page suivante de résultats | ### `google_groups_get_member` @@ -139,7 +141,7 @@ Obtenir les détails d'un membre spécifique dans un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `member` | json | Objet de membre | ### `google_groups_add_member` @@ -157,7 +159,7 @@ Ajouter un nouveau membre à un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `member` | json | Objet de membre ajouté | ### `google_groups_remove_member` @@ -174,7 +176,7 @@ Supprimer un membre d'un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `message` | string | Message de succès | ### `google_groups_update_member` @@ -192,7 +194,7 @@ Mettre à jour un membre | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `member` | json | Objet de membre mis à jour | ### `google_groups_has_member` @@ -209,7 +211,7 @@ Vérifier si un utilisateur est membre d'un groupe Google | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Google Groups | +| `isMember` | boolean | Indique si l'utilisateur est membre du groupe | ## Notes diff --git a/apps/docs/content/docs/fr/tools/google_vault.mdx b/apps/docs/content/docs/fr/tools/google_vault.mdx index 26171eeada..f9ee8d4ab4 100644 --- a/apps/docs/content/docs/fr/tools/google_vault.mdx +++ b/apps/docs/content/docs/fr/tools/google_vault.mdx @@ -35,8 +35,7 @@ Créer une exportation dans une affaire | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé \(UserFile\) depuis les fichiers d'exécution | +| `export` | json | Objet d'exportation créé | ### `google_vault_list_matters_export` @@ -55,8 +54,9 @@ Lister les exportations pour une affaire | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé \(UserFile\) depuis les fichiers d'exécution | +| `exports` | json | Tableau d'objets d'exportation | +| `export` | json | Objet d'exportation unique \(lorsque exportId est fourni\) | +| `nextPageToken` | string | Jeton pour récupérer la page suivante de résultats | ### `google_vault_download_export_file` @@ -95,8 +95,7 @@ Créer une suspension dans une affaire | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé \(UserFile\) depuis les fichiers d'exécution | +| `hold` | json | Objet de suspension créé | ### `google_vault_list_matters_holds` @@ -115,8 +114,9 @@ Lister les suspensions pour une affaire | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé (UserFile) à partir des fichiers d'exécution | +| `holds` | json | Tableau d'objets de suspension | +| `hold` | json | Objet de suspension unique \(lorsque holdId est fourni\) | +| `nextPageToken` | string | Jeton pour récupérer la page suivante de résultats | ### `google_vault_create_matters` @@ -133,8 +133,7 @@ Créer une nouvelle affaire dans Google Vault | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé (UserFile) à partir des fichiers d'exécution | +| `matter` | json | Objet d'affaire créé | ### `google_vault_list_matters` @@ -152,8 +151,9 @@ Lister les affaires, ou obtenir une affaire spécifique si matterId est fourni | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `output` | json | Données de réponse de l'API Vault | -| `file` | json | Fichier d'exportation téléchargé (UserFile) à partir des fichiers d'exécution | +| `matters` | json | Tableau d'objets d'affaire | +| `matter` | json | Objet d'affaire unique \(lorsque matterId est fourni\) | +| `nextPageToken` | string | Jeton pour récupérer la page suivante de résultats | ## Notes diff --git a/apps/docs/content/docs/fr/tools/hubspot.mdx b/apps/docs/content/docs/fr/tools/hubspot.mdx index 4c790615ad..c5ccacf832 100644 --- a/apps/docs/content/docs/fr/tools/hubspot.mdx +++ b/apps/docs/content/docs/fr/tools/hubspot.mdx @@ -48,8 +48,9 @@ Récupérer tous les utilisateurs du compte HubSpot | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `users` | array | Tableau d'objets utilisateur HubSpot | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des utilisateurs | ### `hubspot_list_contacts` @@ -68,8 +69,10 @@ Récupérer tous les contacts du compte HubSpot avec prise en charge de la pagin | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Données des contacts | +| `contacts` | array | Tableau d'objets contact HubSpot | +| `paging` | object | Informations de pagination | +| `metadata` | object | Métadonnées de l'opération | +| `success` | boolean | Statut de réussite de l'opération | ### `hubspot_get_contact` @@ -88,8 +91,9 @@ Récupérer un seul contact par ID ou email depuis HubSpot | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Données du contact | +| `contact` | object | Objet contact HubSpot avec propriétés | +| `metadata` | object | Métadonnées de l'opération | +| `success` | boolean | Statut de réussite de l'opération | ### `hubspot_create_contact` @@ -106,8 +110,9 @@ Créer un nouveau contact dans HubSpot. Nécessite au moins l'un des éléments | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Données du contact créé | +| `contact` | object | Objet contact HubSpot créé | +| `metadata` | object | Métadonnées de l'opération | +| `success` | boolean | Statut de réussite de l'opération | ### `hubspot_update_contact` @@ -125,8 +130,9 @@ Mettre à jour un contact existant dans HubSpot par ID ou email | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Données du contact mis à jour | +| `contact` | object | Objet contact HubSpot mis à jour | +| `metadata` | object | Métadonnées de l'opération | +| `success` | boolean | Statut de réussite de l'opération | ### `hubspot_search_contacts` @@ -147,8 +153,11 @@ Rechercher des contacts dans HubSpot en utilisant des filtres, des tris et des r | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `contacts` | array | Tableau d'objets contact HubSpot correspondants | +| `total` | number | Nombre total de contacts correspondants | +| `paging` | object | Informations de pagination | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Résultats de la recherche | ### `hubspot_list_companies` @@ -167,8 +176,10 @@ Récupérer toutes les entreprises du compte HubSpot avec prise en charge de la | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `companies` | array | Tableau d'objets entreprise HubSpot | +| `paging` | object | Informations de pagination | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des entreprises | ### `hubspot_get_company` @@ -187,8 +198,9 @@ Récupérer une seule entreprise par ID ou domaine depuis HubSpot | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `company` | object | Objet entreprise HubSpot avec propriétés | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données de l'entreprise | ### `hubspot_create_company` @@ -205,8 +217,9 @@ Créer une nouvelle entreprise dans HubSpot | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `company` | object | Objet entreprise HubSpot créé | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données de l'entreprise créée | ### `hubspot_update_company` @@ -224,8 +237,9 @@ Mettre à jour une entreprise existante dans HubSpot par ID ou domaine | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `company` | object | Objet entreprise HubSpot mis à jour | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données de l'entreprise mises à jour | ### `hubspot_search_companies` @@ -246,8 +260,11 @@ Rechercher des entreprises dans HubSpot en utilisant des filtres, des tris et de | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `companies` | array | Tableau d'objets entreprise HubSpot correspondants | +| `total` | number | Nombre total d'entreprises correspondantes | +| `paging` | object | Informations de pagination | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Résultats de la recherche | ### `hubspot_list_deals` @@ -266,8 +283,10 @@ Récupérer toutes les affaires du compte HubSpot avec prise en charge de la pag | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Tableau d'objets affaire HubSpot | +| `paging` | object | Informations de pagination | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des offres | ## Notes diff --git a/apps/docs/content/docs/fr/tools/pipedrive.mdx b/apps/docs/content/docs/fr/tools/pipedrive.mdx index b0c7e00657..170c556efc 100644 --- a/apps/docs/content/docs/fr/tools/pipedrive.mdx +++ b/apps/docs/content/docs/fr/tools/pipedrive.mdx @@ -51,8 +51,9 @@ Récupérer toutes les affaires de Pipedrive avec des filtres optionnels | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Tableau d'objets d'affaires de Pipedrive | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données et métadonnées des affaires | ### `pipedrive_get_deal` @@ -68,8 +69,9 @@ Récupérer des informations détaillées sur une affaire spécifique | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | Objet d'affaire avec tous les détails | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails de l'affaire | ### `pipedrive_create_deal` @@ -93,8 +95,9 @@ Créer une nouvelle affaire dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | L'objet d'affaire créé | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails de l'affaire créée | ### `pipedrive_update_deal` @@ -115,8 +118,9 @@ Mettre à jour une affaire existante dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deal` | object | L'objet d'affaire mis à jour | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails de l'affaire mise à jour | ### `pipedrive_get_files` @@ -135,8 +139,9 @@ Récupérer des fichiers depuis Pipedrive avec des filtres optionnels | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `files` | array | Tableau d'objets fichiers de Pipedrive | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des fichiers | ### `pipedrive_get_mail_messages` @@ -153,8 +158,9 @@ Récupérer les fils de discussion de la boîte mail Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `messages` | array | Tableau d'objets de fils de discussion de la boîte mail Pipedrive | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des fils de discussion | ### `pipedrive_get_mail_thread` @@ -170,8 +176,9 @@ Récupérer tous les messages d'un fil de discussion spécifique | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `messages` | array | Tableau d'objets de messages électroniques du fil de discussion | +| `metadata` | object | Métadonnées de l'opération incluant l'ID du fil de discussion | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des messages du fil de discussion | ### `pipedrive_get_pipelines` @@ -190,8 +197,9 @@ Récupérer tous les pipelines de Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `pipelines` | array | Tableau d'objets de pipeline de Pipedrive | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des pipelines | ### `pipedrive_get_pipeline_deals` @@ -210,8 +218,9 @@ Récupérer toutes les affaires dans un pipeline spécifique | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `deals` | array | Tableau d'objets d'affaires du pipeline | +| `metadata` | object | Métadonnées de l'opération incluant l'ID du pipeline | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des affaires du pipeline | ### `pipedrive_get_projects` @@ -229,8 +238,10 @@ Récupérer tous les projets ou un projet spécifique de Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `projects` | array | Tableau d'objets de projet (lors du listage de tous) | +| `project` | object | Objet de projet unique (lorsque project_id est fourni) | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des projets ou détails d'un projet unique | ### `pipedrive_create_project` @@ -249,8 +260,9 @@ Créer un nouveau projet dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `project` | object | L'objet du projet créé | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails du projet créé | ### `pipedrive_get_activities` @@ -271,8 +283,9 @@ Récupérer les activités (tâches) de Pipedrive avec filtres optionnels | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `activities` | array | Tableau d'objets d'activité de Pipedrive | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des activités | ### `pipedrive_create_activity` @@ -296,8 +309,9 @@ Créer une nouvelle activité (tâche) dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `success` | booléen | Statut de réussite de l'opération | -| `output` | objet | Détails de l'activité créée | +| `activity` | object | L'objet activité créé | +| `metadata` | object | Métadonnées de l'opération | +| `success` | boolean | Statut de réussite de l'opération | ### `pipedrive_update_activity` @@ -319,8 +333,9 @@ Mettre à jour une activité existante (tâche) dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `activity` | object | L'objet activité mis à jour | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails de l'activité mise à jour | ### `pipedrive_get_leads` @@ -341,8 +356,10 @@ Récupérer tous les prospects ou un prospect spécifique depuis Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `leads` | array | Tableau d'objets prospect \(lors de la liste complète\) | +| `lead` | object | Objet prospect unique \(lorsque lead_id est fourni\) | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Données des prospects ou détails d'un prospect spécifique | ### `pipedrive_create_lead` @@ -365,8 +382,9 @@ Créer un nouveau prospect dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `lead` | object | L'objet prospect créé | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails du lead créé | ### `pipedrive_update_lead` @@ -390,8 +408,9 @@ Mettre à jour un lead existant dans Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `lead` | object | L'objet prospect mis à jour | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Détails du lead mis à jour | ### `pipedrive_delete_lead` @@ -407,8 +426,9 @@ Supprimer un lead spécifique de Pipedrive | Paramètre | Type | Description | | --------- | ---- | ----------- | +| `data` | object | Données de confirmation de suppression | +| `metadata` | object | Métadonnées de l'opération | | `success` | boolean | Statut de réussite de l'opération | -| `output` | object | Résultat de la suppression | ## Notes diff --git a/apps/docs/content/docs/fr/tools/sqs.mdx b/apps/docs/content/docs/fr/tools/sqs.mdx index 656f0cc3f1..2321131ce1 100644 --- a/apps/docs/content/docs/fr/tools/sqs.mdx +++ b/apps/docs/content/docs/fr/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: Se connecter à Amazon SQS --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -40,22 +40,22 @@ Envoyer un message à une file d'attente Amazon SQS #### Entrée -| Paramètre | Type | Obligatoire | Description | -| ------------------------ | ------ | ----------- | ----------------------------------------------------------------------------- | -| `region` | string | Oui | Région AWS (par ex., us-east-1) | -| `accessKeyId` | string | Oui | ID de clé d'accès AWS | -| `secretAccessKey` | string | Oui | Clé d'accès secrète AWS | -| `queueUrl` | string | Oui | URL de la file d'attente (par ex., https://sqs.us-east-1.amazonaws.com/123456789012/my-queue) | -| `data` | object | Oui | Corps du message à envoyer sous forme d'objet JSON | -| `messageGroupId` | string | Non | ID de groupe de messages (facultatif) | -| `messageDeduplicationId` | string | Non | ID de déduplication de message pour les files d'attente FIFO (facultatif) | +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `region` | string | Oui | Région AWS (par ex., us-east-1) | +| `accessKeyId` | string | Oui | ID de clé d'accès AWS | +| `secretAccessKey` | string | Oui | Clé d'accès secrète AWS | +| `queueUrl` | string | Oui | URL de la file d'attente | +| `data` | object | Oui | Corps du message à envoyer | +| `messageGroupId` | string | Non | ID de groupe de messages (facultatif) | +| `messageDeduplicationId` | string | Non | ID de déduplication de message (facultatif) | #### Sortie -| Paramètre | Type | Description | -| --------- | ------ | --------------------------------------------------------- | -| `message` | chaîne | Message de succès ou d'erreur décrivant le résultat de l'opération | -| `id` | chaîne | ID du message | +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Message d'état de l'opération | +| `id` | string | ID du message | ## Notes diff --git a/apps/docs/content/docs/fr/tools/typeform.mdx b/apps/docs/content/docs/fr/tools/typeform.mdx index 8792390066..9a3373390a 100644 --- a/apps/docs/content/docs/fr/tools/typeform.mdx +++ b/apps/docs/content/docs/fr/tools/typeform.mdx @@ -48,25 +48,9 @@ Récupérer les réponses aux formulaires depuis Typeform | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `total_items` | nombre | Nombre total de réponses/formulaires | -| `page_count` | nombre | Nombre total de pages | -| `items` | json | Tableau des éléments de réponse/formulaire | -| `id` | chaîne | Identifiant unique du formulaire | -| `title` | chaîne | Titre du formulaire | -| `type` | chaîne | Type de formulaire | -| `created_at` | chaîne | Horodatage ISO de création du formulaire | -| `last_updated_at` | chaîne | Horodatage ISO de la dernière mise à jour | -| `settings` | json | Objet des paramètres du formulaire | -| `theme` | json | Objet de configuration du thème | -| `workspace` | json | Informations sur l'espace de travail | -| `fields` | json | Tableau des champs/questions du formulaire | -| `thankyou_screens` | json | Tableau des écrans de remerciement | -| `_links` | json | Liens vers les ressources associées | -| `deleted` | booléen | Indique si le formulaire a été supprimé avec succès | -| `message` | chaîne | Message de confirmation de suppression | -| `fileUrl` | chaîne | URL du fichier téléchargé | -| `contentType` | chaîne | Type de contenu du fichier | -| `filename` | chaîne | Nom du fichier | +| `total_items` | nombre | Nombre total de réponses | +| `page_count` | nombre | Nombre total de pages disponibles | +| `items` | tableau | Tableau d'objets de réponse avec response_id, submitted_at, answers et metadata | ### `typeform_files` @@ -128,7 +112,7 @@ Récupérer la liste de tous les formulaires dans votre compte Typeform | --------- | ---- | ----------- | | `total_items` | nombre | Nombre total de formulaires dans le compte | | `page_count` | nombre | Nombre total de pages disponibles | -| `items` | tableau | Tableau d'objets de formulaire | +| `items` | tableau | Tableau d'objets de formulaire avec id, title, created_at, last_updated_at, settings, theme et _links | ### `typeform_get_form` @@ -148,11 +132,13 @@ Récupérer les détails complets et la structure d'un formulaire spécifique | `id` | chaîne | Identifiant unique du formulaire | | `title` | chaîne | Titre du formulaire | | `type` | chaîne | Type de formulaire \(form, quiz, etc.\) | -| `created_at` | chaîne | Horodatage ISO de création du formulaire | -| `last_updated_at` | chaîne | Horodatage ISO de la dernière mise à jour | | `settings` | objet | Paramètres du formulaire incluant langue, barre de progression, etc. | -| `theme` | objet | Configuration du thème avec couleurs, polices et paramètres de design | -| `workspace` | objet | Informations sur l'espace de travail | +| `theme` | objet | Référence du thème | +| `workspace` | objet | Référence de l'espace de travail | +| `fields` | tableau | Tableau des champs/questions du formulaire | +| `welcome_screens` | tableau | Tableau des écrans d'accueil | +| `thankyou_screens` | tableau | Tableau des écrans de remerciement | +| `_links` | objet | Liens vers les ressources associées, y compris l'URL publique du formulaire | ### `typeform_create_form` @@ -177,13 +163,8 @@ Créer un nouveau formulaire avec champs et paramètres | `id` | chaîne | Identifiant unique du formulaire créé | | `title` | chaîne | Titre du formulaire | | `type` | chaîne | Type de formulaire | -| `created_at` | chaîne | Horodatage ISO de création du formulaire | -| `last_updated_at` | chaîne | Horodatage ISO de la dernière mise à jour | -| `settings` | objet | Paramètres du formulaire | -| `theme` | objet | Configuration du thème appliqué | -| `workspace` | objet | Informations sur l'espace de travail | -| `fields` | tableau | Tableau des champs de formulaire créés | -| `_links` | objet | Liens vers les ressources associées | +| `fields` | tableau | Tableau des champs du formulaire créé | +| `_links` | objet | Liens vers les ressources associées, y compris l'URL publique du formulaire | ### `typeform_update_form` @@ -204,12 +185,11 @@ Mettre à jour un formulaire existant à l'aide d'opérations JSON Patch | `id` | chaîne | Identifiant unique du formulaire mis à jour | | `title` | chaîne | Titre du formulaire | | `type` | chaîne | Type de formulaire | -| `created_at` | chaîne | Horodatage ISO de création du formulaire | -| `last_updated_at` | chaîne | Horodatage ISO de la dernière mise à jour | | `settings` | objet | Paramètres du formulaire | -| `theme` | objet | Configuration du thème | -| `workspace` | objet | Informations sur l'espace de travail | +| `theme` | objet | Référence du thème | +| `workspace` | objet | Référence de l'espace de travail | | `fields` | tableau | Tableau des champs du formulaire | +| `welcome_screens` | tableau | Tableau des écrans d'accueil | | `thankyou_screens` | tableau | Tableau des écrans de remerciement | | `_links` | objet | Liens vers les ressources associées | diff --git a/apps/docs/content/docs/ja/tools/asana.mdx b/apps/docs/content/docs/ja/tools/asana.mdx index baf639efcb..d9ba23acc0 100644 --- a/apps/docs/content/docs/ja/tools/asana.mdx +++ b/apps/docs/content/docs/ja/tools/asana.mdx @@ -33,8 +33,15 @@ GIDで単一のタスクを取得するか、フィルターを使用して複 | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | taskGidが提供されたかどうかに応じて、単一のタスクの詳細またはタスクの配列 | +| `success` | boolean | 操作成功ステータス | +| `ts` | string | レスポンスのタイムスタンプ | +| `gid` | string | タスクのグローバル一意識別子 | +| `resource_type` | string | リソースタイプ(タスク) | +| `resource_subtype` | string | リソースのサブタイプ | +| `name` | string | タスク名 | +| `notes` | string | タスクのメモや説明 | +| `completed` | boolean | タスクが完了しているかどうか | +| `assignee` | object | 担当者の詳細 | ### `asana_create_task` @@ -54,8 +61,14 @@ Asanaで新しいタスクを作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | タイムスタンプ、GID、名前、メモ、パーマリンクを含む作成されたタスクの詳細 | +| `success` | boolean | 操作成功ステータス | +| `ts` | string | レスポンスのタイムスタンプ | +| `gid` | string | タスクのグローバル一意識別子 | +| `name` | string | タスク名 | +| `notes` | string | タスクのメモや説明 | +| `completed` | boolean | タスクが完了しているかどうか | +| `created_at` | string | タスク作成のタイムスタンプ | +| `permalink_url` | string | Asana内のタスクへのURL | ### `asana_update_task` @@ -77,7 +90,12 @@ Asanaの既存タスクを更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功ステータス | -| `output` | object | タイムスタンプ、gid、名前、メモ、更新タイムスタンプを含む更新されたタスクの詳細 | +| `ts` | string | レスポンスのタイムスタンプ | +| `gid` | string | タスクのグローバル一意識別子 | +| `name` | string | タスク名 | +| `notes` | string | タスクのメモや説明 | +| `completed` | boolean | タスクが完了しているかどうか | +| `modified_at` | string | タスクの最終更新タイムスタンプ | ### `asana_get_projects` @@ -94,7 +112,8 @@ Asanaワークスペースからすべてのプロジェクトを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功ステータス | -| `output` | object | gid、名前、リソースタイプを含むプロジェクトのリスト | +| `ts` | string | レスポンスのタイムスタンプ | +| `projects` | array | プロジェクトの配列 | ### `asana_search_tasks` @@ -115,7 +134,8 @@ Asanaワークスペース内のタスクを検索する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功ステータス | -| `output` | object | 検索条件に一致するタスクのリスト | +| `ts` | string | レスポンスのタイムスタンプ | +| `tasks` | array | 一致するタスクの配列 | ### `asana_add_comment` @@ -133,7 +153,11 @@ Asanaタスクにコメント(ストーリー)を追加する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功ステータス | -| `output` | object | gid、テキスト、作成タイムスタンプ、作成者を含むコメントの詳細 | +| `ts` | string | レスポンスのタイムスタンプ | +| `gid` | string | コメントのグローバル一意識別子 | +| `text` | string | コメントのテキスト内容 | +| `created_at` | string | コメント作成タイムスタンプ | +| `created_by` | object | コメント投稿者の詳細 | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/confluence.mdx b/apps/docs/content/docs/ja/tools/confluence.mdx index 44b07303ff..c6426b4a75 100644 --- a/apps/docs/content/docs/ja/tools/confluence.mdx +++ b/apps/docs/content/docs/ja/tools/confluence.mdx @@ -221,6 +221,33 @@ Confluenceページからコメントを削除します。 | `commentId` | string | 削除されたコメントID | | `deleted` | boolean | 削除ステータス | +### `confluence_upload_attachment` + +ファイルをConfluenceページに添付ファイルとしてアップロードします。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `domain` | string | はい | あなたのConfluenceドメイン(例:yourcompany.atlassian.net) | +| `pageId` | string | はい | ファイルを添付するConfluenceページID | +| `file` | file | はい | 添付ファイルとしてアップロードするファイル | +| `fileName` | string | いいえ | 添付ファイルのオプションのカスタムファイル名 | +| `comment` | string | いいえ | 添付ファイルに追加するオプションのコメント | +| `cloudId` | string | いいえ | インスタンスのConfluence Cloud ID。提供されない場合、ドメインを使用して取得されます。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `ts` | string | アップロードのタイムスタンプ | +| `attachmentId` | string | アップロードされた添付ファイルID | +| `title` | string | 添付ファイル名 | +| `fileSize` | number | ファイルサイズ(バイト単位) | +| `mediaType` | string | 添付ファイルのMIMEタイプ | +| `downloadUrl` | string | 添付ファイルのダウンロードURL | +| `pageId` | string | 添付ファイルが追加されたページID | + ### `confluence_list_attachments` Confluenceページのすべての添付ファイルを一覧表示します。 @@ -282,7 +309,7 @@ Confluenceページのすべてのラベルを一覧表示します。 ### `confluence_get_space` -特定のConfluenceスペースの詳細を取得します。 +特定のConfluenceスペースに関する詳細を取得します。 #### 入力 diff --git a/apps/docs/content/docs/ja/tools/google_groups.mdx b/apps/docs/content/docs/ja/tools/google_groups.mdx index 6f36eeb808..951bebdefd 100644 --- a/apps/docs/content/docs/ja/tools/google_groups.mdx +++ b/apps/docs/content/docs/ja/tools/google_groups.mdx @@ -34,7 +34,8 @@ Google Workspaceドメイン内のすべてのグループを一覧表示する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google グループ API レスポンスデータ | +| `groups` | json | グループオブジェクトの配列 | +| `nextPageToken` | string | 次のページの結果を取得するためのトークン | ### `google_groups_get_group` @@ -50,7 +51,7 @@ Google Workspaceドメイン内のすべてのグループを一覧表示する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google グループ API レスポンスデータ | +| `group` | json | グループオブジェクト | ### `google_groups_create_group` @@ -68,7 +69,7 @@ Google Workspaceドメイン内のすべてのグループを一覧表示する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIのレスポンスデータ | +| `group` | json | 作成されたグループオブジェクト | ### `google_groups_update_group` @@ -87,7 +88,7 @@ Google Workspaceドメイン内のすべてのグループを一覧表示する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIのレスポンスデータ | +| `group` | json | 更新されたグループオブジェクト | ### `google_groups_delete_group` @@ -103,7 +104,7 @@ Googleグループを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIのレスポンスデータ | +| `message` | string | 成功メッセージ | ### `google_groups_list_members` @@ -122,7 +123,8 @@ Google グループのすべてのメンバーを一覧表示する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIのレスポンスデータ | +| `members` | json | メンバーオブジェクトの配列 | +| `nextPageToken` | string | 次のページの結果を取得するためのトークン | ### `google_groups_get_member` @@ -139,7 +141,7 @@ Google グループ内の特定のメンバーの詳細を取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIのレスポンスデータ | +| `member` | json | メンバーオブジェクト | ### `google_groups_add_member` @@ -157,7 +159,7 @@ Google グループに新しいメンバーを追加する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIレスポンスデータ | +| `member` | json | 追加されたメンバーオブジェクト | ### `google_groups_remove_member` @@ -174,7 +176,7 @@ Google Groupからメンバーを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIレスポンスデータ | +| `message` | string | 成功メッセージ | ### `google_groups_update_member` @@ -192,7 +194,7 @@ Google Groupからメンバーを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google Groups APIレスポンスデータ | +| `member` | json | 更新されたメンバーオブジェクト | ### `google_groups_has_member` @@ -209,7 +211,7 @@ Google Groupからメンバーを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Google グループ API レスポンスデータ | +| `isMember` | boolean | ユーザーがグループのメンバーであるかどうか | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/google_vault.mdx b/apps/docs/content/docs/ja/tools/google_vault.mdx index 0575dd6185..c8524755db 100644 --- a/apps/docs/content/docs/ja/tools/google_vault.mdx +++ b/apps/docs/content/docs/ja/tools/google_vault.mdx @@ -34,8 +34,7 @@ Google Vaultに接続して、案件内のエクスポートの作成、エク | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードしたエクスポートファイル(UserFile) | +| `export` | json | 作成されたエクスポートオブジェクト | ### `google_vault_list_matters_export` @@ -54,8 +53,9 @@ Google Vaultに接続して、案件内のエクスポートの作成、エク | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードしたエクスポートファイル(UserFile) | +| `exports` | json | エクスポートオブジェクトの配列 | +| `export` | json | 単一のエクスポートオブジェクト(exportIdが提供された場合) | +| `nextPageToken` | string | 結果の次のページを取得するためのトークン | ### `google_vault_download_export_file` @@ -94,8 +94,7 @@ Google Vaultエクスポート(GCSオブジェクト)から単一ファイ | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードしたエクスポートファイル(UserFile) | +| `hold` | json | 作成された保留オブジェクト | ### `google_vault_list_matters_holds` @@ -112,10 +111,11 @@ Google Vaultエクスポート(GCSオブジェクト)から単一ファイ #### 出力 -| パラメータ | タイプ | 説明 | +| パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードされたエクスポートファイル(UserFile) | +| `holds` | json | 保留オブジェクトの配列 | +| `hold` | json | 単一の保留オブジェクト(holdIdが提供された場合) | +| `nextPageToken` | string | 結果の次のページを取得するためのトークン | ### `google_vault_create_matters` @@ -130,10 +130,9 @@ Google Vaultで新しい案件を作成する #### 出力 -| パラメータ | タイプ | 説明 | +| パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードされたエクスポートファイル(UserFile) | +| `matter` | json | 作成された案件オブジェクト | ### `google_vault_list_matters` @@ -149,10 +148,11 @@ Google Vaultで新しい案件を作成する #### 出力 -| パラメータ | タイプ | 説明 | +| パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `output` | json | Vault APIレスポンスデータ | -| `file` | json | 実行ファイルからダウンロードされたエクスポートファイル(UserFile) | +| `matters` | json | 案件オブジェクトの配列 | +| `matter` | json | 単一の案件オブジェクト(matterIdが提供された場合) | +| `nextPageToken` | string | 結果の次のページを取得するためのトークン | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/hubspot.mdx b/apps/docs/content/docs/ja/tools/hubspot.mdx index 3f5bad5925..4aa9a3782b 100644 --- a/apps/docs/content/docs/ja/tools/hubspot.mdx +++ b/apps/docs/content/docs/ja/tools/hubspot.mdx @@ -47,8 +47,9 @@ HubSpotアカウントからすべてのユーザーを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | ユーザーデータ | +| `users` | array | HubSpotユーザーオブジェクトの配列 | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `hubspot_list_contacts` @@ -67,8 +68,10 @@ HubSpotアカウントからすべてのユーザーを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `contacts` | array | HubSpotコンタクトオブジェクトの配列 | +| `paging` | object | ページネーション情報 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | コンタクトデータ | ### `hubspot_get_contact` @@ -87,8 +90,9 @@ HubSpotからIDまたはメールで単一のコンタクトを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `contact` | object | プロパティを持つHubSpotコンタクトオブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | コンタクトデータ | ### `hubspot_create_contact` @@ -105,8 +109,9 @@ HubSpotで新しい連絡先を作成します。少なくともemail、firstnam | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | 作成された連絡先データ | +| `contact` | object | 作成されたHubSpotコンタクトオブジェクト | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `hubspot_update_contact` @@ -124,8 +129,9 @@ IDまたはメールアドレスでHubSpotの既存の連絡先を更新しま | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | 更新された連絡先データ | +| `contact` | object | 更新されたHubSpotコンタクトオブジェクト | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `hubspot_search_contacts` @@ -146,8 +152,11 @@ IDまたはメールアドレスでHubSpotの既存の連絡先を更新しま | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | 検索結果 | +| `contacts` | array | 一致するHubSpotコンタクトオブジェクトの配列 | +| `total` | number | 一致するコンタクトの総数 | +| `paging` | object | ページネーション情報 | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `hubspot_list_companies` @@ -166,8 +175,10 @@ IDまたはメールアドレスでHubSpotの既存の連絡先を更新しま | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | 企業データ | +| `companies` | array | HubSpot会社オブジェクトの配列 | +| `paging` | object | ページネーション情報 | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `hubspot_get_company` @@ -186,8 +197,9 @@ IDまたはドメインからHubSpotの単一企業を取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `company` | object | プロパティを持つHubSpot会社オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 企業データ | ### `hubspot_create_company` @@ -204,8 +216,9 @@ HubSpotに新しい企業を作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `company` | object | 作成されたHubSpot会社オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 作成された企業データ | ### `hubspot_update_company` @@ -223,8 +236,9 @@ IDまたはドメインによってHubSpotの既存企業を更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `company` | object | 更新されたHubSpot会社オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 更新された会社データ | ### `hubspot_search_companies` @@ -245,8 +259,11 @@ IDまたはドメインによってHubSpotの既存企業を更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `companies` | array | 一致するHubSpot会社オブジェクトの配列 | +| `total` | number | 一致する会社の総数 | +| `paging` | object | ページネーション情報 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 検索結果 | ### `hubspot_list_deals` @@ -265,8 +282,10 @@ IDまたはドメインによってHubSpotの既存企業を更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deals` | array | HubSpotディールオブジェクトの配列 | +| `paging` | object | ページネーション情報 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 取引データ | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/pipedrive.mdx b/apps/docs/content/docs/ja/tools/pipedrive.mdx index 4f60fa967e..63e0d3a825 100644 --- a/apps/docs/content/docs/ja/tools/pipedrive.mdx +++ b/apps/docs/content/docs/ja/tools/pipedrive.mdx @@ -51,8 +51,9 @@ Pipedriveをワークフローに統合します。強力なCRM機能を使用 | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deals` | array | Pipedriveからの取引オブジェクトの配列 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 取引データとメタデータ | ### `pipedrive_get_deal` @@ -68,8 +69,9 @@ Pipedriveをワークフローに統合します。強力なCRM機能を使用 | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deal` | object | 詳細情報を含む取引オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 取引の詳細 | ### `pipedrive_create_deal` @@ -93,8 +95,9 @@ Pipedriveで新しい取引を作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deal` | object | 作成された取引オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 作成されたディールの詳細 | ### `pipedrive_update_deal` @@ -115,8 +118,9 @@ Pipedriveの既存のディールを更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deal` | object | 更新された取引オブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 更新されたディールの詳細 | ### `pipedrive_get_files` @@ -135,8 +139,9 @@ Pipedriveの既存のディールを更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `files` | array | Pipedriveからのファイルオブジェクトの配列 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | ファイルデータ | ### `pipedrive_get_mail_messages` @@ -153,8 +158,9 @@ Pipedriveメールボックスからメールスレッドを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `messages` | array | Pipedriveメールボックスからのメールスレッドオブジェクトの配列 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | メールスレッドデータ | ### `pipedrive_get_mail_thread` @@ -170,8 +176,9 @@ Pipedriveメールボックスからメールスレッドを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `messages` | array | スレッドからのメールメッセージオブジェクトの配列 | +| `metadata` | object | スレッドIDを含む操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | メールスレッドメッセージデータ | ### `pipedrive_get_pipelines` @@ -190,8 +197,9 @@ Pipedriveからすべてのパイプラインを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `pipelines` | array | Pipedriveからのパイプラインオブジェクトの配列 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | パイプラインデータ | ### `pipedrive_get_pipeline_deals` @@ -210,8 +218,9 @@ Pipedriveからすべてのパイプラインを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `deals` | array | パイプラインからの取引オブジェクトの配列 | +| `metadata` | object | パイプラインIDを含む操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | パイプライン取引データ | ### `pipedrive_get_projects` @@ -229,8 +238,10 @@ Pipedriveからすべてのプロジェクトまたは特定のプロジェク | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `projects` | array | プロジェクトオブジェクトの配列(すべてをリスト表示する場合) | +| `project` | object | 単一のプロジェクトオブジェクト(project_idが提供される場合) | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | プロジェクトデータまたは単一プロジェクトの詳細 | ### `pipedrive_create_project` @@ -249,8 +260,9 @@ Pipedriveで新しいプロジェクトを作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `project` | object | 作成されたプロジェクトオブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 作成されたプロジェクトの詳細 | ### `pipedrive_get_activities` @@ -271,8 +283,9 @@ Pipedriveで新しいプロジェクトを作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `activities` | array | Pipedriveからのアクティビティオブジェクトの配列 | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | アクティビティデータ | ### `pipedrive_create_activity` @@ -296,8 +309,9 @@ Pipedriveで新しいアクティビティ(タスク)を作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `success` | boolean | 操作の成功ステータス | -| `output` | object | 作成されたアクティビティの詳細 | +| `activity` | object | 作成されたアクティビティオブジェクト | +| `metadata` | object | 操作メタデータ | +| `success` | boolean | 操作成功ステータス | ### `pipedrive_update_activity` @@ -319,8 +333,9 @@ Pipedriveで既存のアクティビティ(タスク)を更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `activity` | object | 更新されたアクティビティオブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 更新されたアクティビティの詳細 | ### `pipedrive_get_leads` @@ -341,8 +356,10 @@ Pipedriveからすべてのリードまたは特定のリードを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `leads` | array | リード オブジェクトの配列(すべてをリスト表示する場合) | +| `lead` | object | 単一のリード オブジェクト(lead_id が提供される場合) | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | リードデータまたは単一リードの詳細 | ### `pipedrive_create_lead` @@ -365,8 +382,9 @@ Pipedriveに新しいリードを作成する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `lead` | object | 作成されたリードオブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 作成されたリードの詳細 | ### `pipedrive_update_lead` @@ -390,8 +408,9 @@ Pipedriveの既存リードを更新する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `lead` | object | 更新されたリードオブジェクト | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 更新されたリードの詳細 | ### `pipedrive_delete_lead` @@ -407,8 +426,9 @@ Pipedriveから特定のリードを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | +| `data` | object | 削除確認データ | +| `metadata` | object | 操作メタデータ | | `success` | boolean | 操作成功ステータス | -| `output` | object | 削除結果 | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/sqs.mdx b/apps/docs/content/docs/ja/tools/sqs.mdx index 04e8232744..03838251f1 100644 --- a/apps/docs/content/docs/ja/tools/sqs.mdx +++ b/apps/docs/content/docs/ja/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: Amazon SQSに接続 --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -40,22 +40,22 @@ Amazon SQSキューにメッセージを送信 #### 入力 -| パラメータ | 型 | 必須 | 説明 | -| ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | -| `region` | string | はい | AWSリージョン(例:us-east-1) | -| `accessKeyId` | string | はい | AWSアクセスキーID | -| `secretAccessKey` | string | はい | AWSシークレットアクセスキー | -| `queueUrl` | string | はい | キューURL(例:https://sqs.us-east-1.amazonaws.com/123456789012/my-queue)| -| `data` | object | はい | JSONオブジェクトとして送信するメッセージ本文 | -| `messageGroupId` | string | いいえ | メッセージグループID(オプション) | -| `messageDeduplicationId` | string | いいえ | FIFOキュー用のメッセージ重複排除ID(オプション) | +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `region` | string | はい | AWS リージョン(例:us-east-1) | +| `accessKeyId` | string | はい | AWS アクセスキーID | +| `secretAccessKey` | string | はい | AWS シークレットアクセスキー | +| `queueUrl` | string | はい | キューURL | +| `data` | object | はい | 送信するメッセージ本文 | +| `messageGroupId` | string | いいえ | メッセージグループID(オプション) | +| `messageDeduplicationId` | string | いいえ | メッセージ重複排除ID(オプション) | #### 出力 -| パラメータ | 型 | 説明 | -| --------- | ------ | --------------------------------------------------------- | -| `message` | string | 操作結果を説明する成功またはエラーメッセージ | -| `id` | string | メッセージID | +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `message` | string | 操作ステータスメッセージ | +| `id` | string | メッセージID | ## 注意事項 diff --git a/apps/docs/content/docs/ja/tools/typeform.mdx b/apps/docs/content/docs/ja/tools/typeform.mdx index e4f4847143..47087eb685 100644 --- a/apps/docs/content/docs/ja/tools/typeform.mdx +++ b/apps/docs/content/docs/ja/tools/typeform.mdx @@ -48,25 +48,9 @@ Typeformからフォームの回答を取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `total_items` | number | 回答/フォームの総数 | -| `page_count` | number | 総ページ数 | -| `items` | json | 回答/フォーム項目の配列 | -| `id` | string | フォームの一意の識別子 | -| `title` | string | フォームのタイトル | -| `type` | string | フォームのタイプ | -| `created_at` | string | フォーム作成のISOタイムスタンプ | -| `last_updated_at` | string | 最終更新のISOタイムスタンプ | -| `settings` | json | フォーム設定オブジェクト | -| `theme` | json | テーマ設定オブジェクト | -| `workspace` | json | ワークスペース情報 | -| `fields` | json | フォームフィールド/質問の配列 | -| `thankyou_screens` | json | サンキュースクリーンの配列 | -| `_links` | json | 関連リソースリンク | -| `deleted` | boolean | フォームが正常に削除されたかどうか | -| `message` | string | 削除確認メッセージ | -| `fileUrl` | string | ダウンロードされたファイルのURL | -| `contentType` | string | ファイルのコンテンツタイプ | -| `filename` | string | ファイル名 | +| `total_items` | number | 回答の総数 | +| `page_count` | number | 利用可能なページの総数 | +| `items` | array | response_id、submitted_at、answers、およびmetadataを含む回答オブジェクトの配列 | ### `typeform_files` @@ -127,8 +111,8 @@ Typeformアカウント内のすべてのフォームのリストを取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `total_items` | number | アカウント内のフォームの総数 | -| `page_count` | number | 利用可能な総ページ数 | -| `items` | array | フォームオブジェクトの配列 | +| `page_count` | number | 利用可能なページの総数 | +| `items` | array | id、title、created_at、last_updated_at、settings、theme、および_linksを含むフォームオブジェクトの配列 | ### `typeform_get_form` @@ -148,11 +132,13 @@ Typeformアカウント内のすべてのフォームのリストを取得する | `id` | string | フォームの一意の識別子 | | `title` | string | フォームのタイトル | | `type` | string | フォームのタイプ(form、quizなど) | -| `created_at` | string | フォーム作成のISOタイムスタンプ | -| `last_updated_at` | string | 最終更新のISOタイムスタンプ | -| `settings` | object | 言語、進捗バーなどを含むフォーム設定 | -| `theme` | object | 色、フォント、デザイン設定を含むテーマ構成 | -| `workspace` | object | ワークスペース情報 | +| `settings` | object | 言語、プログレスバーなどを含むフォーム設定 | +| `theme` | object | テーマ参照 | +| `workspace` | object | ワークスペース参照 | +| `fields` | array | フォームフィールド/質問の配列 | +| `welcome_screens` | array | ウェルカム画面の配列 | +| `thankyou_screens` | array | サンキュー画面の配列 | +| `_links` | object | 公開フォームURLを含む関連リソースリンク | ### `typeform_create_form` @@ -177,13 +163,8 @@ Typeformアカウント内のすべてのフォームのリストを取得する | `id` | string | 作成されたフォームの一意の識別子 | | `title` | string | フォームのタイトル | | `type` | string | フォームのタイプ | -| `created_at` | string | フォーム作成のISOタイムスタンプ | -| `last_updated_at` | string | 最終更新のISOタイムスタンプ | -| `settings` | object | フォーム設定 | -| `theme` | object | 適用されたテーマ設定 | -| `workspace` | object | ワークスペース情報 | | `fields` | array | 作成されたフォームフィールドの配列 | -| `_links` | object | 関連リソースリンク | +| `_links` | object | 公開フォームURLを含む関連リソースリンク | ### `typeform_update_form` @@ -204,13 +185,12 @@ JSON Patchオペレーションを使用して既存のフォームを更新す | `id` | string | 更新されたフォームの一意の識別子 | | `title` | string | フォームのタイトル | | `type` | string | フォームのタイプ | -| `created_at` | string | フォーム作成のISOタイムスタンプ | -| `last_updated_at` | string | 最終更新のISOタイムスタンプ | | `settings` | object | フォーム設定 | -| `theme` | object | テーマ設定 | -| `workspace` | object | ワークスペース情報 | +| `theme` | object | テーマ参照 | +| `workspace` | object | ワークスペース参照 | | `fields` | array | フォームフィールドの配列 | -| `thankyou_screens` | array | サンキュー画面の配列 | +| `welcome_screens` | array | ウェルカム画面の配列 | +| `thankyou_screens` | array | サンクスページの配列 | | `_links` | object | 関連リソースリンク | ### `typeform_delete_form` diff --git a/apps/docs/content/docs/zh/tools/asana.mdx b/apps/docs/content/docs/zh/tools/asana.mdx index 1c32239641..46d23ae9b0 100644 --- a/apps/docs/content/docs/zh/tools/asana.mdx +++ b/apps/docs/content/docs/zh/tools/asana.mdx @@ -34,7 +34,14 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 单个任务详情或任务数组,取决于是否提供了 taskGid | +| `ts` | string | 响应的时间戳 | +| `gid` | string | 任务的全局唯一标识符 | +| `resource_type` | string | 资源类型(任务) | +| `resource_subtype` | string | 资源子类型 | +| `name` | string | 任务名称 | +| `notes` | string | 任务备注或描述 | +| `completed` | boolean | 任务是否已完成 | +| `assignee` | object | 分配人详情 | ### `asana_create_task` @@ -55,7 +62,13 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 包含时间戳、gid、名称、备注和永久链接的已创建任务详情 | +| `ts` | string | 响应的时间戳 | +| `gid` | string | 任务的全局唯一标识符 | +| `name` | string | 任务名称 | +| `notes` | string | 任务备注或描述 | +| `completed` | boolean | 任务是否已完成 | +| `created_at` | string | 任务创建时间戳 | +| `permalink_url` | string | 任务在 Asana 中的 URL | ### `asana_update_task` @@ -77,7 +90,12 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 更新的任务详情,包括时间戳、gid、名称、备注和修改时间戳 | +| `ts` | string | 响应的时间戳 | +| `gid` | string | 任务的全局唯一标识符 | +| `name` | string | 任务名称 | +| `notes` | string | 任务备注或描述 | +| `completed` | boolean | 任务是否已完成 | +| `modified_at` | string | 任务最后修改时间戳 | ### `asana_get_projects` @@ -94,7 +112,8 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 项目列表,包括它们的 gid、名称和资源类型 | +| `ts` | string | 响应的时间戳 | +| `projects` | array | 项目数组 | ### `asana_search_tasks` @@ -115,7 +134,8 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 符合搜索条件的任务列表 | +| `ts` | string | 响应的时间戳 | +| `tasks` | array | 匹配任务的数组 | ### `asana_add_comment` @@ -133,7 +153,11 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `success` | boolean | 操作成功状态 | -| `output` | object | 评论详情,包括 gid、文本、创建时间戳和作者 | +| `ts` | string | 响应的时间戳 | +| `gid` | string | 评论的全局唯一标识符 | +| `text` | string | 评论的文本内容 | +| `created_at` | string | 评论的创建时间戳 | +| `created_by` | object | 评论作者的详细信息 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/confluence.mdx b/apps/docs/content/docs/zh/tools/confluence.mdx index f74f7ff16f..ed1033d898 100644 --- a/apps/docs/content/docs/zh/tools/confluence.mdx +++ b/apps/docs/content/docs/zh/tools/confluence.mdx @@ -220,6 +220,33 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | `commentId` | string | 删除的评论 ID | | `deleted` | boolean | 删除状态 | +### `confluence_upload_attachment` + +将文件作为附件上传到 Confluence 页面。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `domain` | string | 是 | 您的 Confluence 域名 \(例如:yourcompany.atlassian.net\) | +| `pageId` | string | 是 | 要附加文件的 Confluence 页面 ID | +| `file` | file | 是 | 要作为附件上传的文件 | +| `fileName` | string | 否 | 附件的可选自定义文件名 | +| `comment` | string | 否 | 附件的可选评论 | +| `cloudId` | string | 否 | 实例的 Confluence Cloud ID。如果未提供,将使用域名进行获取。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `ts` | string | 上传的时间戳 | +| `attachmentId` | string | 上传的附件 ID | +| `title` | string | 附件文件名 | +| `fileSize` | number | 文件大小(以字节为单位) | +| `mediaType` | string | 附件的 MIME 类型 | +| `downloadUrl` | string | 附件的下载 URL | +| `pageId` | string | 添加附件的页面 ID | + ### `confluence_list_attachments` 列出 Confluence 页面上的所有附件。 @@ -230,7 +257,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | --------- | ---- | -------- | ----------- | | `domain` | string | 是 | 您的 Confluence 域名 \(例如:yourcompany.atlassian.net\) | | `pageId` | string | 是 | 要列出附件的 Confluence 页面 ID | -| `limit` | number | 否 | 返回的附件最大数量 \(默认值:25\) | +| `limit` | number | 否 | 返回的最大附件数量 \(默认值:25\) | | `cloudId` | string | 否 | 实例的 Confluence Cloud ID。如果未提供,将使用域名进行获取。 | #### 输出 @@ -257,7 +284,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `ts` | string | 删除的时间戳 | -| `attachmentId` | string | 已删除的附件 ID | +| `attachmentId` | string | 删除的附件 ID | | `deleted` | boolean | 删除状态 | ### `confluence_list_labels` @@ -281,7 +308,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" ### `confluence_get_space` -获取特定 Confluence 空间的详细信息。 +获取有关特定 Confluence 空间的详细信息。 #### 输入 diff --git a/apps/docs/content/docs/zh/tools/google_groups.mdx b/apps/docs/content/docs/zh/tools/google_groups.mdx index 4e61b6a5c6..cdb03b8374 100644 --- a/apps/docs/content/docs/zh/tools/google_groups.mdx +++ b/apps/docs/content/docs/zh/tools/google_groups.mdx @@ -34,7 +34,8 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `groups` | json | 群组对象的数组 | +| `nextPageToken` | string | 用于获取下一页结果的令牌 | ### `google_groups_get_group` @@ -50,7 +51,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `group` | json | 群组对象 | ### `google_groups_create_group` @@ -68,7 +69,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `group` | json | 创建的群组对象 | ### `google_groups_update_group` @@ -87,7 +88,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `group` | json | 更新的群组对象 | ### `google_groups_delete_group` @@ -103,7 +104,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `message` | string | 成功消息 | ### `google_groups_list_members` @@ -122,7 +123,8 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `members` | json | 成员对象的数组 | +| `nextPageToken` | string | 用于获取下一页结果的令牌 | ### `google_groups_get_member` @@ -139,7 +141,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `member` | json | 成员对象 | ### `google_groups_add_member` @@ -157,7 +159,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `member` | json | 添加的成员对象 | ### `google_groups_remove_member` @@ -174,7 +176,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `message` | string | 成功消息 | ### `google_groups_update_member` @@ -192,7 +194,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `member` | json | 更新的成员对象 | ### `google_groups_has_member` @@ -209,7 +211,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Google Groups API 响应数据 | +| `isMember` | boolean | 用户是否是该群组的成员 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/google_vault.mdx b/apps/docs/content/docs/zh/tools/google_vault.mdx index 144b20a2f6..f149956fbc 100644 --- a/apps/docs/content/docs/zh/tools/google_vault.mdx +++ b/apps/docs/content/docs/zh/tools/google_vault.mdx @@ -34,8 +34,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `export` | json | 创建的导出对象 | ### `google_vault_list_matters_export` @@ -54,8 +53,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `exports` | json | 导出对象的数组 | +| `export` | json | 单个导出对象(当提供 exportId 时) | +| `nextPageToken` | string | 用于获取下一页结果的令牌 | ### `google_vault_download_export_file` @@ -94,8 +94,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `hold` | json | 创建的保留对象 | ### `google_vault_list_matters_holds` @@ -114,8 +113,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `holds` | json | 保留对象的数组 | +| `hold` | json | 单个保留对象(当提供 holdId 时) | +| `nextPageToken` | string | 用于获取下一页结果的令牌 | ### `google_vault_create_matters` @@ -132,8 +132,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `matter` | json | 创建的事项对象 | ### `google_vault_list_matters` @@ -151,8 +150,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `output` | json | Vault API 响应数据 | -| `file` | json | 从执行文件中下载的导出文件 \(UserFile\) | +| `matters` | json | 事项对象的数组 | +| `matter` | json | 单个事项对象(当提供 matterId 时) | +| `nextPageToken` | string | 用于获取下一页结果的令牌 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/hubspot.mdx b/apps/docs/content/docs/zh/tools/hubspot.mdx index ef2b99a87d..f7928e05e7 100644 --- a/apps/docs/content/docs/zh/tools/hubspot.mdx +++ b/apps/docs/content/docs/zh/tools/hubspot.mdx @@ -47,8 +47,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 用户数据 | +| `users` | 数组 | HubSpot 用户对象的数组 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_list_contacts` @@ -67,8 +68,10 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 联系人数据 | +| `contacts` | 数组 | HubSpot 联系人对象的数组 | +| `paging` | 对象 | 分页信息 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_get_contact` @@ -87,8 +90,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 联系人数据 | +| `contact` | 对象 | 带有属性的 HubSpot 联系人对象 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_create_contact` @@ -105,8 +109,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 创建的联系人数据 | +| `contact` | 对象 | 创建的 HubSpot 联系人对象 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_update_contact` @@ -124,8 +129,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 更新的联系人数据 | +| `contact` | 对象 | 更新的 HubSpot 联系人对象 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_search_contacts` @@ -146,8 +152,11 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | boolean | 操作成功状态 | -| `output` | object | 搜索结果 | +| `contacts` | 数组 | 匹配的 HubSpot 联系人对象的数组 | +| `total` | 数字 | 匹配的联系人总数 | +| `paging` | 对象 | 分页信息 | +| `metadata` | 对象 | 操作元数据 | +| `success` | 布尔值 | 操作成功状态 | ### `hubspot_list_companies` @@ -166,8 +175,10 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `companies` | array | HubSpot 公司对象的数组 | +| `paging` | object | 分页信息 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 公司数据 | ### `hubspot_get_company` @@ -186,8 +197,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `company` | object | 带有属性的 HubSpot 公司对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 公司数据 | ### `hubspot_create_company` @@ -204,8 +216,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `company` | object | 创建的 HubSpot 公司对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 创建的公司数据 | ### `hubspot_update_company` @@ -223,8 +236,9 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `company` | object | 更新的 HubSpot 公司对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 更新的公司数据 | ### `hubspot_search_companies` @@ -245,8 +259,11 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `companies` | array | 匹配的 HubSpot 公司对象的数组 | +| `total` | number | 匹配的公司总数 | +| `paging` | object | 分页信息 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 搜索结果 | ### `hubspot_list_deals` @@ -265,8 +282,10 @@ HubSpot CRM 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `success` | 布尔值 | 操作成功状态 | -| `output` | 对象 | 交易数据 | +| `deals` | array | HubSpot 交易对象的数组 | +| `paging` | object | 分页信息 | +| `metadata` | object | 操作元数据 | +| `success` | boolean | 操作成功状态 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/pipedrive.mdx b/apps/docs/content/docs/zh/tools/pipedrive.mdx index 5c73d902a4..bf63821e76 100644 --- a/apps/docs/content/docs/zh/tools/pipedrive.mdx +++ b/apps/docs/content/docs/zh/tools/pipedrive.mdx @@ -51,8 +51,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `deals` | array | 来自 Pipedrive 的交易对象数组 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 交易数据和元数据 | ### `pipedrive_get_deal` @@ -68,8 +69,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `deal` | object | 包含完整详细信息的交易对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 交易详情 | ### `pipedrive_create_deal` @@ -93,8 +95,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `deal` | object | 创建的交易对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 创建的交易详情 | ### `pipedrive_update_deal` @@ -115,8 +118,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `deal` | object | 更新的交易对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 更新的交易详情 | ### `pipedrive_get_files` @@ -135,8 +139,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `files` | array | 来自 Pipedrive 的文件对象数组 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 文件数据 | ### `pipedrive_get_mail_messages` @@ -153,8 +158,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `messages` | array | 来自 Pipedrive 邮箱的邮件线程对象数组 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 邮件线程数据 | ### `pipedrive_get_mail_thread` @@ -170,8 +176,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `messages` | array | 邮件线程中的邮件消息对象数组 | +| `metadata` | object | 包含线程 ID 的操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 邮件线程消息数据 | ### `pipedrive_get_pipelines` @@ -190,8 +197,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `pipelines` | array | 来自 Pipedrive 的管道对象数组 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 管道数据 | ### `pipedrive_get_pipeline_deals` @@ -210,8 +218,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `deals` | array | 管道中的交易对象数组 | +| `metadata` | object | 包含管道 ID 的操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 管道交易数据 | ### `pipedrive_get_projects` @@ -229,8 +238,10 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `projects` | array | 项目对象数组(列出所有项目时) | +| `project` | object | 单个项目对象(提供 project_id 时) | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 项目数据或单个项目详情 | ### `pipedrive_create_project` @@ -249,8 +260,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `project` | object | 创建的项目对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 创建的项目详情 | ### `pipedrive_get_activities` @@ -271,8 +283,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `activities` | array | 来自 Pipedrive 的活动对象数组 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 活动数据 | ### `pipedrive_create_activity` @@ -296,8 +309,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `activity` | object | 创建的活动对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 创建的活动详情 | ### `pipedrive_update_activity` @@ -319,8 +333,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `activity` | object | 更新的活动对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 更新的活动详情 | ### `pipedrive_get_leads` @@ -341,8 +356,10 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `leads` | array | 潜在客户对象数组(列出所有时) | +| `lead` | object | 单个潜在客户对象(提供 lead_id 时) | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 潜在客户数据或单个潜在客户详情 | ### `pipedrive_create_lead` @@ -365,8 +382,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `lead` | object | 创建的潜在客户对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 创建的潜在客户详情 | ### `pipedrive_update_lead` @@ -390,8 +408,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `lead` | object | 更新的潜在客户对象 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 更新的潜在客户详情 | ### `pipedrive_delete_lead` @@ -407,8 +426,9 @@ Pipedrive 的主要功能包括: | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | +| `data` | object | 删除确认数据 | +| `metadata` | object | 操作元数据 | | `success` | boolean | 操作成功状态 | -| `output` | object | 删除结果 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/sqs.mdx b/apps/docs/content/docs/zh/tools/sqs.mdx index 7ba2785a98..e5ed5a678c 100644 --- a/apps/docs/content/docs/zh/tools/sqs.mdx +++ b/apps/docs/content/docs/zh/tools/sqs.mdx @@ -3,9 +3,9 @@ title: Amazon SQS description: 连接到 Amazon SQS --- -import { BlockInfoCard } from "@/components/ui/block-info-card"; +import { BlockInfoCard } from "@/components/ui/block-info-card" - @@ -40,22 +40,22 @@ import { BlockInfoCard } from "@/components/ui/block-info-card"; #### 输入 -| 参数 | 类型 | 必需 | 描述 | -| ------------------------ | ------ | ------ | -------------------------------------------------------------------------- | -| `region` | string | 是 | AWS 区域 \(例如,us-east-1\) | -| `accessKeyId` | string | 是 | AWS 访问密钥 ID | -| `secretAccessKey` | string | 是 | AWS 秘密访问密钥 | -| `queueUrl` | string | 是 | 队列 URL \(例如,https://sqs.us-east-1.amazonaws.com/123456789012/my-queue\) | -| `data` | object | 是 | 要作为 JSON 对象发送的消息正文 | -| `messageGroupId` | string | 否 | 消息组 ID \(可选\) | -| `messageDeduplicationId` | string | 否 | FIFO 队列的消息去重 ID \(可选\) | +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `region` | string | 是 | AWS 区域 \(例如,us-east-1\) | +| `accessKeyId` | string | 是 | AWS 访问密钥 ID | +| `secretAccessKey` | string | 是 | AWS 秘密访问密钥 | +| `queueUrl` | string | 是 | 队列 URL | +| `data` | object | 是 | 要发送的消息正文 | +| `messageGroupId` | string | 否 | 消息组 ID \(可选\) | +| `messageDeduplicationId` | string | 否 | 消息去重 ID \(可选\) | #### 输出 -| 参数 | 类型 | 描述 | -| --------- | ------ | --------------------------------------------------------- | -| `message` | string | 描述操作结果的成功或错误信息 | -| `id` | string | 消息 ID | +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `message` | string | 操作状态消息 | +| `id` | string | 消息 ID | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/typeform.mdx b/apps/docs/content/docs/zh/tools/typeform.mdx index f1e5454536..1e79963c28 100644 --- a/apps/docs/content/docs/zh/tools/typeform.mdx +++ b/apps/docs/content/docs/zh/tools/typeform.mdx @@ -48,25 +48,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `total_items` | number | 响应/表单总数 | -| `page_count` | number | 总页数 | -| `items` | json | 响应/表单项目数组 | -| `id` | string | 表单唯一标识符 | -| `title` | string | 表单标题 | -| `type` | string | 表单类型 | -| `created_at` | string | 表单创建的 ISO 时间戳 | -| `last_updated_at` | string | 上次更新的 ISO 时间戳 | -| `settings` | json | 表单设置对象 | -| `theme` | json | 主题配置对象 | -| `workspace` | json | 工作区信息 | -| `fields` | json | 表单字段/问题数组 | -| `thankyou_screens` | json | 感谢页面数组 | -| `_links` | json | 相关资源链接 | -| `deleted` | boolean | 表单是否成功删除 | -| `message` | string | 删除确认消息 | -| `fileUrl` | string | 下载文件的 URL | -| `contentType` | string | 文件内容类型 | -| `filename` | string | 文件名 | +| `total_items` | number | 响应的总数 | +| `page_count` | number | 可用页面的总数 | +| `items` | array | 包含 response_id、submitted_at、answers 和 metadata 的响应对象数组 | ### `typeform_files` @@ -126,9 +110,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `total_items` | number | 帐户中表单的总数 | +| `total_items` | number | 账户中的表单总数 | | `page_count` | number | 可用页面的总数 | -| `items` | array | 表单对象的数组 | +| `items` | array | 包含 id、title、created_at、last_updated_at、settings、theme 和 _links 的表单对象数组 | ### `typeform_get_form` @@ -147,12 +131,14 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | --------- | ---- | ----------- | | `id` | string | 表单唯一标识符 | | `title` | string | 表单标题 | -| `type` | string | 表单类型 \(表单、测验等\) | -| `created_at` | string | 表单创建的 ISO 时间戳 | -| `last_updated_at` | string | 上次更新的 ISO 时间戳 | +| `type` | string | 表单类型 \(form, quiz 等\) | | `settings` | object | 表单设置,包括语言、进度条等 | -| `theme` | object | 主题配置,包括颜色、字体和设计设置 | -| `workspace` | object | 工作区信息 | +| `theme` | object | 主题引用 | +| `workspace` | object | 工作区引用 | +| `fields` | array | 表单字段/问题数组 | +| `welcome_screens` | array | 欢迎页面数组 | +| `thankyou_screens` | array | 感谢页面数组 | +| `_links` | object | 包括公共表单 URL 在内的相关资源链接 | ### `typeform_create_form` @@ -177,13 +163,8 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | `id` | string | 创建的表单唯一标识符 | | `title` | string | 表单标题 | | `type` | string | 表单类型 | -| `created_at` | string | 表单创建的 ISO 时间戳 | -| `last_updated_at` | string | 最后更新的 ISO 时间戳 | -| `settings` | object | 表单设置 | -| `theme` | object | 应用的主题配置 | -| `workspace` | object | 工作区信息 | | `fields` | array | 创建的表单字段数组 | -| `_links` | object | 相关资源链接 | +| `_links` | object | 包括公共表单 URL 在内的相关资源链接 | ### `typeform_update_form` @@ -204,13 +185,12 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | `id` | string | 更新的表单唯一标识符 | | `title` | string | 表单标题 | | `type` | string | 表单类型 | -| `created_at` | string | 表单创建的 ISO 时间戳 | -| `last_updated_at` | string | 最后更新的 ISO 时间戳 | | `settings` | object | 表单设置 | -| `theme` | object | 主题配置 | -| `workspace` | object | 工作区信息 | +| `theme` | object | 主题引用 | +| `workspace` | object | 工作区引用 | | `fields` | array | 表单字段数组 | -| `thankyou_screens` | array | 感谢页面数组 | +| `welcome_screens` | array | 欢迎屏幕数组 | +| `thankyou_screens` | array | 感谢屏幕数组 | | `_links` | object | 相关资源链接 | ### `typeform_delete_form` diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index 2c1756375b..0a862912b2 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -477,7 +477,7 @@ checksums: content/11: 371d0e46b4bd2c23f559b8bc112f6955 content/12: f86b4f5f2c68f43bb30c31455e3be9b6 content/13: bcadfc362b69078beee0088e5936c98b - content/14: a29319a7824fc50f83f50b8d616371d4 + content/14: 5112eece1ec6b0be680f45e1135a3281 content/15: 0bf7daaa3e25f831e867651f1f741b42 content/16: 194950d92c8162c418cb14eec4ab5a18 content/17: 371d0e46b4bd2c23f559b8bc112f6955 @@ -495,25 +495,25 @@ checksums: content/29: 371d0e46b4bd2c23f559b8bc112f6955 content/30: 1cc22f14b53f6cb1508c9d9e76a97ffc content/31: bcadfc362b69078beee0088e5936c98b - content/32: 52de3b8f239d1c17c53364d781b0e644 + content/32: bfb1f1db8e96160f94f6edb40fa3faad content/33: 13f4e18c7e77c96613108cfe64e4d364 content/34: aaada0cb81a7e70297d9d47f936e51fd content/35: 371d0e46b4bd2c23f559b8bc112f6955 content/36: 4c6a3b159dfff0106b67269130253eba content/37: bcadfc362b69078beee0088e5936c98b - content/38: 93282e29fd004417112ebfee716b2e29 + content/38: 21cc925781120afc2c4568f74ed8191a content/39: 5de052cae5ada1f845f7257ba431ebd1 content/40: 1a36fc873771b68a67d95a2130487aec content/41: 371d0e46b4bd2c23f559b8bc112f6955 content/42: b000bca7bd6658d4b5d21e6c7787d05e content/43: bcadfc362b69078beee0088e5936c98b - content/44: 8fa5b975e46b4e488b17cc497de86694 + content/44: 448922b8585b0b4599e7023c80faa449 content/45: 776f62636d112cbd27d5064a40e29ec9 content/46: f512a5096a1d5a4e4a0afd762152b714 content/47: 371d0e46b4bd2c23f559b8bc112f6955 content/48: 06de592289fb5f4dff42f451ebf9658a content/49: bcadfc362b69078beee0088e5936c98b - content/50: d3696981fefa1f9c436e23842f69e172 + content/50: d242a9680311743714a60bf1941ef9ac content/51: a4cfd36d36633eee441423283d4d5fb3 content/52: 85ea23183709f33902aec778c7cb62b0 content/53: 371d0e46b4bd2c23f559b8bc112f6955 @@ -3845,38 +3845,44 @@ checksums: content/60: 5901c2c84678c889c2d48e77b40014ec content/61: bcadfc362b69078beee0088e5936c98b content/62: d76ee741e1888731742798f2794101ed - content/63: 496b5789a744fec56b165a7f7ccbefc0 - content/64: 976b5c09fddc3981a1881e62624fb1f6 + content/63: a81589f2200fc67b255fe43614d22976 + content/64: 37784f302e365fcd636a86adf08c0297 content/65: 371d0e46b4bd2c23f559b8bc112f6955 - content/66: c9ea0e2c6bfb9abd73572d021f74a7de + content/66: fed65968404d4a377eaf8d2387a15926 content/67: bcadfc362b69078beee0088e5936c98b - content/68: e01308629566a2c3e95cc26304188ef0 - content/69: 1de796fec3488fe36d6e811727a916a9 - content/70: 75f92c54e71d2734e3901343240ab29e + content/68: bdfc6b8dc4f285b5636054bda5073f28 + content/69: 496b5789a744fec56b165a7f7ccbefc0 + content/70: 976b5c09fddc3981a1881e62624fb1f6 content/71: 371d0e46b4bd2c23f559b8bc112f6955 - content/72: 2e80241a94359c7165b7eee705674e31 + content/72: c9ea0e2c6bfb9abd73572d021f74a7de content/73: bcadfc362b69078beee0088e5936c98b - content/74: e843dcc7e9c933e4a5747379c1e51f2e - content/75: 72c749dd7c4c64b84e8764c606c9599e - content/76: d3feee2154fc7a46b842e2435a649727 + content/74: e01308629566a2c3e95cc26304188ef0 + content/75: 1de796fec3488fe36d6e811727a916a9 + content/76: 75f92c54e71d2734e3901343240ab29e content/77: 371d0e46b4bd2c23f559b8bc112f6955 - content/78: 7465a5023e6ba134f07e12e588a85671 + content/78: 2e80241a94359c7165b7eee705674e31 content/79: bcadfc362b69078beee0088e5936c98b - content/80: a2817ce70b061ae3f2c1bf62c4078001 - content/81: 119c212dac0135f1ccedfbf0eb8d27ae - content/82: 83dd6ad7872478f4ec41b4362792b883 + content/80: e843dcc7e9c933e4a5747379c1e51f2e + content/81: 72c749dd7c4c64b84e8764c606c9599e + content/82: d3feee2154fc7a46b842e2435a649727 content/83: 371d0e46b4bd2c23f559b8bc112f6955 - content/84: d2acf911462ae4e825d47e8a386d6d1c + content/84: 7465a5023e6ba134f07e12e588a85671 content/85: bcadfc362b69078beee0088e5936c98b - content/86: f69940bcedadf67b0e474682577207cf - content/87: db73fc05316809b28857ca697ceeffe7 - content/88: 3277861c34a8958c3a6d47b5978ae867 + content/86: a2817ce70b061ae3f2c1bf62c4078001 + content/87: 119c212dac0135f1ccedfbf0eb8d27ae + content/88: 83dd6ad7872478f4ec41b4362792b883 content/89: 371d0e46b4bd2c23f559b8bc112f6955 - content/90: 07003e71b6286e0588f606d8e063c783 + content/90: d2acf911462ae4e825d47e8a386d6d1c content/91: bcadfc362b69078beee0088e5936c98b - content/92: 5c0becafe66dc048e541fe7330336c3f - content/93: b3f310d5ef115bea5a8b75bf25d7ea9a - content/94: 05207a2c6155f6912f2945a2ca85d5fc + content/92: f69940bcedadf67b0e474682577207cf + content/93: db73fc05316809b28857ca697ceeffe7 + content/94: 3277861c34a8958c3a6d47b5978ae867 + content/95: 371d0e46b4bd2c23f559b8bc112f6955 + content/96: 07003e71b6286e0588f606d8e063c783 + content/97: bcadfc362b69078beee0088e5936c98b + content/98: 5c0becafe66dc048e541fe7330336c3f + content/99: b3f310d5ef115bea5a8b75bf25d7ea9a + content/100: 05207a2c6155f6912f2945a2ca85d5fc 63c9ac4220dfb233b39daaa9c82ade00: meta/title: 50de3a91960f18340fe2672a889fcfd7 meta/description: 4dd9ce8fa67af977678af57427c65e0b @@ -5674,13 +5680,13 @@ checksums: content/7: 371d0e46b4bd2c23f559b8bc112f6955 content/8: a3c11477d8439403d831759eaf853014 content/9: bcadfc362b69078beee0088e5936c98b - content/10: f383a8845c0fe57f4eb82c1c69009925 + content/10: 845660ec2cdd9b96a52f7fd6edb7e069 content/11: 6ec042e76b23443637c5318f52794824 content/12: 8b5f9dc14880c8c000fb31d2609b472d content/13: 371d0e46b4bd2c23f559b8bc112f6955 content/14: 0a261f4aa9ed78d0d064e2bb0d62044c content/15: bcadfc362b69078beee0088e5936c98b - content/16: f383a8845c0fe57f4eb82c1c69009925 + content/16: e69b63114342a49f24a67f2867164814 content/17: da5389d425a2ed3cfc699b8b305b92ca content/18: 2f8d4817554dde3883597dc00beb677a content/19: 371d0e46b4bd2c23f559b8bc112f6955 @@ -5692,25 +5698,25 @@ checksums: content/25: 371d0e46b4bd2c23f559b8bc112f6955 content/26: d5b98c983daa7d8b92969933a797b4fd content/27: bcadfc362b69078beee0088e5936c98b - content/28: f383a8845c0fe57f4eb82c1c69009925 + content/28: ba52aed0f57ba4b4616a67f7648c2d3b content/29: 156255b2849bbf28a1aa98516dee39e1 content/30: 226995d6023bacd5ebeb6568cef38d32 content/31: 371d0e46b4bd2c23f559b8bc112f6955 content/32: 3d10386c77486a8fb7777eb2e616762f content/33: bcadfc362b69078beee0088e5936c98b - content/34: f383a8845c0fe57f4eb82c1c69009925 + content/34: 2556172bac9279ba61689e93a75077cc content/35: e4d7bc479212113e9ce1e4a4bd76f86a content/36: ce9c08055f6ec84a646c1fb90aab9fc4 content/37: 371d0e46b4bd2c23f559b8bc112f6955 content/38: 0f29418fa0c7fe544613330b91940f6a content/39: bcadfc362b69078beee0088e5936c98b - content/40: f383a8845c0fe57f4eb82c1c69009925 + content/40: 60cc1342d1475d0b822aacfcc9d162d8 content/41: 6226071e782ecd50a31e3667852aeaae content/42: 6253ab1d2159b9179728769cc223b05a content/43: 371d0e46b4bd2c23f559b8bc112f6955 content/44: 6ea2166f86fd38641c7cbbf7ff7dde14 content/45: bcadfc362b69078beee0088e5936c98b - content/46: f383a8845c0fe57f4eb82c1c69009925 + content/46: 4c9b5b6404367f05cf17c80f718a9722 content/47: b3f310d5ef115bea5a8b75bf25d7ea9a content/48: 5e1c856b28d30016198e90cda5b05e57 5d496ee293efcfeeabc8ba9cb5bea389: @@ -6698,109 +6704,109 @@ checksums: content/12: 371d0e46b4bd2c23f559b8bc112f6955 content/13: dae5c302ede2453d0009c5a685feb022 content/14: bcadfc362b69078beee0088e5936c98b - content/15: 6fa0deda19439292c55097ef25239c77 + content/15: 1602503ae72d1314b640123d677cc633 content/16: 51bce1eb49f5202343f9826024223b31 content/17: 2350cbe796d8d46f5952029c863fda06 content/18: 371d0e46b4bd2c23f559b8bc112f6955 content/19: 9c06876470db23917a2a3ee5a4315733 content/20: bcadfc362b69078beee0088e5936c98b - content/21: 2e035c1b9af4b2beef1f5b5fdc0f2308 + content/21: 106fd592034d1f004c98d526cf3f3d73 content/22: 7c0ac45f6f6630777a388cffda717b5b content/23: 49cb82a2975f9088dab6b37cf7cc0554 content/24: 371d0e46b4bd2c23f559b8bc112f6955 content/25: 1479d81949322910928d3986fda177c8 content/26: bcadfc362b69078beee0088e5936c98b - content/27: 7a0fbeb1d352c71128b6c71919428414 + content/27: b747e7b327f0dd4ae3672533e4e6eb62 content/28: afb55d14fa0dddda2ff67bdb87aa04b5 content/29: b06d024ce4c861572929702e551501c0 content/30: 371d0e46b4bd2c23f559b8bc112f6955 content/31: e23ce76d94ca15f112c3da007d896376 content/32: bcadfc362b69078beee0088e5936c98b - content/33: d88238e92bd4da31e893dbef2602577f + content/33: 4a8637b7a6dfe444af42778d5dea8953 content/34: 573ed349fb115c8e2b262639eb1cee94 content/35: 2cf83cedde0bf34c0126d10fa57d8ea7 content/36: 371d0e46b4bd2c23f559b8bc112f6955 content/37: ced779c0459899d9934ed9d5e9c16027 content/38: bcadfc362b69078beee0088e5936c98b - content/39: a7eebb30e28a7b07316b224c7a2a8d65 + content/39: a22c0adf9f7af9920ffd005ea77f0973 content/40: 7346be42f9672ab948b276c6bcd6f7f6 content/41: 1aee2da8c1e7b0d6869959103bffb799 content/42: 371d0e46b4bd2c23f559b8bc112f6955 content/43: 87a0ac973fd1af8f8282589860fc9846 content/44: bcadfc362b69078beee0088e5936c98b - content/45: 4c20536f0e8a44cd5f4e4fbac837c84d + content/45: 5963fe44971a0c55f0a1a63305ee0489 content/46: 0a4667f0fe6170c78f12dab6c8f43545 content/47: 168d47bf81f43b2f07f68a6135dc6e20 content/48: 371d0e46b4bd2c23f559b8bc112f6955 content/49: f0e41e3c3b7472bbe309abaaf3251faf content/50: bcadfc362b69078beee0088e5936c98b - content/51: b8d43e8492c521206c7698b16ad47a77 + content/51: 431aa94527010c6e8da4c205ec739e34 content/52: 194e0dcae0b72f23ae9b7d5422a99b33 content/53: 3c4fdc8e069f2802c73471908fddd25a content/54: 371d0e46b4bd2c23f559b8bc112f6955 content/55: 6014a6b6972597a13edc66f8bd65a9a0 content/56: bcadfc362b69078beee0088e5936c98b - content/57: 739083ffe3711c4dfb580ee7f2949343 + content/57: 10e5475e4ba1928c6f409c962d48b1d7 content/58: 53e2acf4473d4182244c34aa421d8a43 content/59: d768c66310b7a829344a7ee4ac897e72 content/60: 371d0e46b4bd2c23f559b8bc112f6955 content/61: cd4caf9d3ae8aef3785a78db4fdadc9f content/62: bcadfc362b69078beee0088e5936c98b - content/63: 9b70d9ae3fda05442e911dee1614f27e + content/63: 680395d47cd8d1134facf052e0a2a38b content/64: 48b29aa751b26ed0f9db1e95e760cd27 content/65: 6b8826b7fe1b3639465cd267f149673a content/66: 371d0e46b4bd2c23f559b8bc112f6955 content/67: bded72160da14ccf151b0a0eb06bb56f content/68: bcadfc362b69078beee0088e5936c98b - content/69: e54159fa3e3620cc49bee79e772cb87e + content/69: e0b7ea1fe1ef728e53492b5993b15d14 content/70: ae4b76165d096d64525d1aee1e18fee0 content/71: a18956fdd8ce9a265626539f75e96084 content/72: 371d0e46b4bd2c23f559b8bc112f6955 content/73: 573b4147d240e71a452c45d772f28b33 content/74: bcadfc362b69078beee0088e5936c98b - content/75: b8aa04222de1cd87b5ef6ffcad8e63fd + content/75: 209a7be82a8c8f943a2b6eae46fdf59d content/76: 4bd432a7a3e1440b6b71f235a6ad65cd content/77: fd8fbeb55ef74c575281f61b04ec31c0 content/78: 371d0e46b4bd2c23f559b8bc112f6955 content/79: e558fa14a8f54ad2957a0715c8fc131d content/80: bcadfc362b69078beee0088e5936c98b - content/81: 5e681a2ba92d15d5efdbd3269bbd595c + content/81: 8cdef68820d5b731b817485136203e2e content/82: a617faea0b4556a3e2cdd76854be4eeb content/83: 3a4f2fec3210cd6caaceaff1ade1d25d content/84: 371d0e46b4bd2c23f559b8bc112f6955 content/85: 6268a8ef99f3c8edfbb54adb702252c2 content/86: bcadfc362b69078beee0088e5936c98b - content/87: 2db32021d8c338ff378c041bdd771b36 + content/87: c4005cf9f2be966687a8e1657053b658 content/88: e594b6968a32cc114836e7d338b2ae72 content/89: ecbe896e30d37803f062d774c3fed61e content/90: 371d0e46b4bd2c23f559b8bc112f6955 content/91: 31bb12c5fecb55e000fb6548ff84611d content/92: bcadfc362b69078beee0088e5936c98b - content/93: cbb110de4c385f111ba0c2cfd2bee9ba + content/93: 13881b819f65455ba6eaa79578a69416 content/94: 232c00f66421f98d3acfe0066c25a861 content/95: 29cea11c97efbd2d46163eb3f091fe54 content/96: 371d0e46b4bd2c23f559b8bc112f6955 content/97: 1e7dbcb716a318b2861889422fdc16cc content/98: bcadfc362b69078beee0088e5936c98b - content/99: bf86387df51e9fba30a22614e23450e0 + content/99: 5642bc5da8834e5c1b825393e59138bb content/100: b9fa49fac9189484fb4952264802b2fa content/101: 730c30b24067e75bf4bd88067281d869 content/102: 371d0e46b4bd2c23f559b8bc112f6955 content/103: 80bad3d5d39d84dddf169515ea34e867 content/104: bcadfc362b69078beee0088e5936c98b - content/105: 1f974e39ff95cbb8f217448e40537a7a + content/105: 8424c37fc3a7ab3c14673df85ffdb97e content/106: 7d3f547f7d19f6f08b6501de082e9d22 content/107: 410cfe5d22625805edc6d68e6cdd9606 content/108: 371d0e46b4bd2c23f559b8bc112f6955 content/109: 5ad03aa50355f0c83f7bb6cb8795a598 content/110: bcadfc362b69078beee0088e5936c98b - content/111: f9e40bfcca798561cf3fa41ecea16079 + content/111: fbcea5843f0ceacfada9473d602b5073 content/112: 940c561f84e0e3cb3c75cf789ce886b8 content/113: 83d531300698c39ce89ff22a4a699722 content/114: 371d0e46b4bd2c23f559b8bc112f6955 content/115: 3015c78bbe4877ab591f25b04f026f1b content/116: bcadfc362b69078beee0088e5936c98b - content/117: 45d8bfeced635336cacc9d4a8d08dbca + content/117: 0db5be06d1f87f79a56b19c0cd33c5d9 content/118: b3f310d5ef115bea5a8b75bf25d7ea9a content/119: 58da44cca95db12222bd186cf4042384 f8151918dd7b32173a979241c19134ba: @@ -6821,73 +6827,73 @@ checksums: content/12: 371d0e46b4bd2c23f559b8bc112f6955 content/13: cf0eb00889d3fbe8f11192fbde69d152 content/14: bcadfc362b69078beee0088e5936c98b - content/15: ddea0f29c3b0b39d4d68accb1ee22f1d + content/15: 903282a17337b15eb942f93814ca7e27 content/16: dacdc7f65574fccd17af803318f08ef9 content/17: 1e91462ed3829658d2ec8c5e19b44276 content/18: 371d0e46b4bd2c23f559b8bc112f6955 content/19: 3f75fb03850d89c3746403ab778e6c6e content/20: bcadfc362b69078beee0088e5936c98b - content/21: a91e46a2855f87996b8dae5dc6a9aaf6 + content/21: 91827ecd0a9656291c376a3ad8f4d496 content/22: 8d068110b8b042b41197680cbcbd0927 content/23: dde6ab55890a4d8cc9327080ce0597c3 content/24: 371d0e46b4bd2c23f559b8bc112f6955 content/25: 3e92d8c3f4040a803e8b607960c29b6c content/26: bcadfc362b69078beee0088e5936c98b - content/27: b74416361f94e71f2a94139711a5dd21 + content/27: 237639e938a067fec5678d0515b7d168 content/28: 713d826a38614b3652126a3fe9c6126f content/29: f5a0bd20a329a7dd67288c689b47e2d9 content/30: 371d0e46b4bd2c23f559b8bc112f6955 content/31: 98ca93ddd2a2aee2f61dec9fe632384a content/32: bcadfc362b69078beee0088e5936c98b - content/33: 59c08999f9c404330ebd8f8a7d21e1a1 + content/33: a911e619373da2bd26a6ab96aec81055 content/34: 7d04f221614ad1354fe3621c30df226d content/35: 7e180b7c89c19f1e2cd120262e57ba38 content/36: 371d0e46b4bd2c23f559b8bc112f6955 content/37: 58087b9c1752a00e213ae852c0bd8809 content/38: bcadfc362b69078beee0088e5936c98b - content/39: a9096a341b00ce4f4891daaca2586d1c + content/39: 299684025f9e6e850ab16d6baf418b26 content/40: 3c244b481f57915598dd929f5b8a23cc content/41: d6d85996497b2381017261d33d5cd1b0 content/42: 371d0e46b4bd2c23f559b8bc112f6955 content/43: 4fac81b063955c77058d3baa9163b3d0 content/44: bcadfc362b69078beee0088e5936c98b - content/45: d84fb23e5dfc9d41a177acd7dfb28e72 + content/45: f49a920a3b7cde671b28907e8b502139 content/46: 5931a0fc92f49d3319a105262d5ca128 content/47: b08cbcbb1e221857dac6f92381f5bcb3 content/48: 371d0e46b4bd2c23f559b8bc112f6955 content/49: 6d1626fc785f9ada58825976e51a31f9 content/50: bcadfc362b69078beee0088e5936c98b - content/51: 024d1b1b1865fe5a64117e56e8787378 + content/51: ccb1eb5dabe073b1c58ab500f799e52f content/52: ebe21f836617d8f9fac6bc1c2adb80f6 content/53: db8df7c9b04b016eeb2b9a47e0719206 content/54: 371d0e46b4bd2c23f559b8bc112f6955 content/55: 66bbc953313a2075ca8598e291251910 content/56: bcadfc362b69078beee0088e5936c98b - content/57: a7e001e39652db8eeb4d32968bda102b + content/57: 368234e1ffbba050e602cfa12151c3ea content/58: 688707edc447f458dd66ed554d4d4b3f content/59: 2a2834d73d8ff43d7e3b4e5bda10325e content/60: 371d0e46b4bd2c23f559b8bc112f6955 content/61: ade51ba73d7a75e12fc928288ff20ea9 content/62: bcadfc362b69078beee0088e5936c98b - content/63: 4c03414c0a9acc3ea28293b627b5b881 + content/63: 7c3270bc6736a2bd7c0f5496d1c5f5ce content/64: 76aaca4f2b31aac6deaeaa1d71882912 content/65: b05b49d0597283e9c4c672f0b45ecda0 content/66: 371d0e46b4bd2c23f559b8bc112f6955 content/67: 0ba45c91fa13677917e47e88297e5a20 content/68: bcadfc362b69078beee0088e5936c98b - content/69: 3155eda71c6003c7382f3f1c7c793c4d + content/69: ddfbf3d4e45cae666af814d9c855f219 content/70: 41fdc537cc5a4f117f4e51b10d4b893c content/71: 2aab9e60a5ddef37cc45e839fd265d10 content/72: 371d0e46b4bd2c23f559b8bc112f6955 content/73: 4fac81b063955c77058d3baa9163b3d0 content/74: bcadfc362b69078beee0088e5936c98b - content/75: d84fb23e5dfc9d41a177acd7dfb28e72 + content/75: 043b526a4286ce4cd2dac146a6e4da9a content/76: 1e064911f29516b36aac2252d09d3264 content/77: 8872c46680fb5433e3e0e0a77e003b22 content/78: 371d0e46b4bd2c23f559b8bc112f6955 content/79: 6d1626fc785f9ada58825976e51a31f9 content/80: bcadfc362b69078beee0088e5936c98b - content/81: fed2311ba97e58ae76786292a757702e + content/81: 4edfee5770f54034f27f9bc59ee7d1f4 content/82: b3f310d5ef115bea5a8b75bf25d7ea9a content/83: dd6d6480c2ae6bc7c827ec9564ec7ef9 ed72a377ba81c1bf04db2423f73d062b: @@ -6903,37 +6909,37 @@ checksums: content/7: 371d0e46b4bd2c23f559b8bc112f6955 content/8: 3266fdc66f47be026e3d85ab90eb7d16 content/9: bcadfc362b69078beee0088e5936c98b - content/10: 365ddc9f29d7be92c2728fa31acd422e + content/10: 2f41e84609ff3ba897a32f8e033b97a4 content/11: 886903f11f98dfe38a6e6f29fdbb8528 content/12: 3d11d1d78714f9e4075abf1953e75419 content/13: 371d0e46b4bd2c23f559b8bc112f6955 content/14: fa21911c64ea75c918e352059eb2fe7f content/15: bcadfc362b69078beee0088e5936c98b - content/16: 73fafa520a11921f8df9fa8d8b587d92 + content/16: 662dacdee0a82c71c7b630238514aaf3 content/17: 82a733d968d25120950aaf9fd928c63c content/18: bef062551faa2678b2112920a5bda1d2 content/19: 371d0e46b4bd2c23f559b8bc112f6955 content/20: 4aeb05322a8d1e939a3b3b64d28f08a5 content/21: bcadfc362b69078beee0088e5936c98b - content/22: 1619572a3d37abd3ce129d2504ecbdcb + content/22: 25e898053049f3125589308873970895 content/23: 5cf8947a4e28bad973b58526cb57d0ab content/24: 0093e8689859deeb465584a5338891fd content/25: 371d0e46b4bd2c23f559b8bc112f6955 content/26: aebeebc35e961034b2800b44d3c8c50a content/27: bcadfc362b69078beee0088e5936c98b - content/28: f0659feb482e9a487ff14d3babc59851 + content/28: 87d76638ba698c2b3e5b8f67377eff5f content/29: 69d5a8e4bf6275107b232f78bb67162a content/30: 37fd64adf8a955b203d31a19bd328878 content/31: 371d0e46b4bd2c23f559b8bc112f6955 content/32: 78657a4d018e378ca7aea2e00d1aa602 content/33: bcadfc362b69078beee0088e5936c98b - content/34: e267b11cdce02732ed71edd6cce119ae + content/34: d05d8d278738bb917a7e0f88ff94458b content/35: 1f5a6b20541ced797f9bf32db70f972d content/36: 9cec30d66167e3a54f01f27b500026f2 content/37: 371d0e46b4bd2c23f559b8bc112f6955 content/38: 1705a4a7e36233333aa624fd7c561bef content/39: bcadfc362b69078beee0088e5936c98b - content/40: 60efbb9e08ce955c225a0e8cf69626be + content/40: 9ca0c224a20194a7efe00c52d1ce3218 content/41: b3f310d5ef115bea5a8b75bf25d7ea9a content/42: e7d074449d490a0eb0f4cbf2ca1886ab b7341c73e73c19fbe18dd999900d8f7c: @@ -48948,67 +48954,67 @@ checksums: content/7: 371d0e46b4bd2c23f559b8bc112f6955 content/8: ddf9f33ab00bc63ba73d935e9a9461bb content/9: bcadfc362b69078beee0088e5936c98b - content/10: 83f29573676a9d1ccb33827ff578858a + content/10: 221e358865139adec497f1cb5d0b1a99 content/11: 16b29a33d78bf2344e7b204ca98c0b82 content/12: 97b8063d8d1ada29666d9ec525694a93 content/13: 371d0e46b4bd2c23f559b8bc112f6955 content/14: 6e295e5dcf37ad9f7ee602652b93c5bf content/15: bcadfc362b69078beee0088e5936c98b - content/16: 83f29573676a9d1ccb33827ff578858a + content/16: 5c47ddc296b16e10a7b1594b7dcfd825 content/17: 20c596f9dbdfe0cfa2d8f5b60dc71514 content/18: 1448d524a996ed212e7dbdbe967339b0 content/19: 371d0e46b4bd2c23f559b8bc112f6955 content/20: 0c9e28a7cf7bcfee1fe692fbd502dbb4 content/21: bcadfc362b69078beee0088e5936c98b - content/22: 83f29573676a9d1ccb33827ff578858a + content/22: f559cd33f4b35b97e66d822945f63137 content/23: 24e966f4a7a7f97a355b749b74377e64 content/24: 968f985de62e1fe2ad21716d7c215fc3 content/25: 371d0e46b4bd2c23f559b8bc112f6955 content/26: fd89e6852579854ef98eef8a76a261c5 content/27: bcadfc362b69078beee0088e5936c98b - content/28: 83f29573676a9d1ccb33827ff578858a + content/28: 08765f663111f814f0f7e0d3343f6cef content/29: 84bf7ab082392d81a1347dd4091df95c content/30: e6d21b5e83b22fcee600f5863114f76b content/31: 371d0e46b4bd2c23f559b8bc112f6955 content/32: 6357650b93cf00ec79d620f75336a063 content/33: bcadfc362b69078beee0088e5936c98b - content/34: 83f29573676a9d1ccb33827ff578858a + content/34: 2b3c80bcbce92fe344b5d92ace204b15 content/35: 9a047f1df87fa8980889528cd4a7e23e content/36: 10a705b69f4de0cafb55b579a091ff3e content/37: 371d0e46b4bd2c23f559b8bc112f6955 content/38: a5f1409dffad379396a370fc6ef0b784 content/39: bcadfc362b69078beee0088e5936c98b - content/40: 83f29573676a9d1ccb33827ff578858a + content/40: 49d0e9315a756ad56e74dd4554d65f25 content/41: bc110e334defc4a0037ba2ef9fb75083 content/42: 741dfd7becb14378932cbad9bd3f1aaa content/43: 371d0e46b4bd2c23f559b8bc112f6955 content/44: 5bf2c3d8e1f679dffa34a23728e09d3d content/45: bcadfc362b69078beee0088e5936c98b - content/46: 83f29573676a9d1ccb33827ff578858a + content/46: ee3bece021d785fa491f484d2647efa9 content/47: 007ad7c8b597dd1638c1d730ae57c18b content/48: 66114378d52751790fb30b1d4a49fb4b content/49: 371d0e46b4bd2c23f559b8bc112f6955 content/50: 2f9f05b2bdf789cfda1791b0a274de0f content/51: bcadfc362b69078beee0088e5936c98b - content/52: 83f29573676a9d1ccb33827ff578858a + content/52: d08b87675acf0952c583781b4344377f content/53: b812f4c86dc86447c8aab2e6fc7ee77b content/54: d368e64c4bc2884ac4af1c046d3043fc content/55: 371d0e46b4bd2c23f559b8bc112f6955 content/56: 8d96a5aad7ba60cbbe6c4ab8b816c8f5 content/57: bcadfc362b69078beee0088e5936c98b - content/58: 83f29573676a9d1ccb33827ff578858a + content/58: 2b3c80bcbce92fe344b5d92ace204b15 content/59: bb444040039dcefd837703242f69b3f2 content/60: 2ca4d597cf85afe0c09441a1c55dc588 content/61: 371d0e46b4bd2c23f559b8bc112f6955 content/62: f90f9e7f20b3c4bf832a71e2dcbc1fe5 content/63: bcadfc362b69078beee0088e5936c98b - content/64: 83f29573676a9d1ccb33827ff578858a + content/64: 41fcb4df99d2ba5f87c86d126a017227 content/65: cdbf6d4d4066c241de37637f23944a51 content/66: 1f1ad7c241c27cf4614ba7b0b67fb584 content/67: 371d0e46b4bd2c23f559b8bc112f6955 content/68: 705cf28994842a8a455ba3dcb61c3f11 content/69: bcadfc362b69078beee0088e5936c98b - content/70: 83f29573676a9d1ccb33827ff578858a + content/70: a03d9bf68ad5a88bf70953996c51b951 content/71: b3f310d5ef115bea5a8b75bf25d7ea9a content/72: fe020be6c017a995d0355c99c6b034ec 1b5c57a63b2d38e097b7f96b6e054db8: @@ -49308,8 +49314,8 @@ checksums: 01bda2a6417895b3b24a3d2b543866d4: meta/title: 55272c40df2a877093c8470e52102e87 meta/description: 13e8a6591a8addf009cb647bb7ee6a0d - content/0: 19c5610b4392aadcf63d11fff6261b71 - content/1: 722f06242bbde726fd9de48cf1762e21 + content/0: 1b031fb0c62c46b177aeed5c3d3f8f80 + content/1: 13c31b22dc8320eea4766871b5bdb2b1 content/2: da04d549734a9cf9c8cc168dbd6952dc content/3: ecde46402d67144e99794c51b616c17d content/4: 8884d8cca8ee6de94be5d8116e2f94b6 @@ -49322,8 +49328,8 @@ checksums: content/11: b1a2d0fd1320fb6a73e3fda153b9c7ae content/12: cba5245faf73a6067d5720b824e1bef0 content/13: 371d0e46b4bd2c23f559b8bc112f6955 - content/14: 16cc4f2c3e461466e347399b60e4b130 + content/14: c93b79e5e1d98454c11e30fc97049725 content/15: bcadfc362b69078beee0088e5936c98b - content/16: 44bff30d972517dcf6be3dd00a8d7e4a + content/16: a064887f5c777b54e029ba6ba1b56848 content/17: b3f310d5ef115bea5a8b75bf25d7ea9a content/18: a4748f8ce0a4667675ca03e4d9fef87b From cb9b88127f9b9785db548cc5dd10fa05d08c235a Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 22:58:01 -0800 Subject: [PATCH 12/34] fix(envvars): added industry standard dotenv parsing regex for adding envvars in settings (#2327) * fix(envvars): added industry standard dotenv parsing regex for adding envvars in settings * ack PR comments * added more edge cases --- .../components/environment/environment.tsx | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/environment/environment.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/environment/environment.tsx index 0c0bfec38a..2f6aae5a6d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/environment/environment.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/environment/environment.tsx @@ -352,13 +352,48 @@ export function EnvironmentVariables({ registerBeforeLeaveHandler }: Environment }, []) const parseEnvVarLine = useCallback((line: string): UIEnvironmentVariable | null => { - const equalIndex = line.indexOf('=') + const trimmed = line.trim() + + if (!trimmed || trimmed.startsWith('#')) return null + + const withoutExport = trimmed.replace(/^export\s+/, '') + + const equalIndex = withoutExport.indexOf('=') if (equalIndex === -1 || equalIndex === 0) return null - const potentialKey = line.substring(0, equalIndex).trim() + const potentialKey = withoutExport.substring(0, equalIndex).trim() if (!ENV_VAR_PATTERN.test(potentialKey)) return null - const value = line.substring(equalIndex + 1).trim() + let value = withoutExport.substring(equalIndex + 1) + + const looksLikeBase64Key = /^[A-Za-z0-9+/]+$/.test(potentialKey) && !potentialKey.includes('_') + const valueIsJustPadding = /^=+$/.test(value.trim()) + if (looksLikeBase64Key && valueIsJustPadding && potentialKey.length > 20) { + return null + } + + const trimmedValue = value.trim() + if ( + !trimmedValue.startsWith('"') && + !trimmedValue.startsWith("'") && + !trimmedValue.startsWith('`') + ) { + const commentIndex = value.search(/\s#/) + if (commentIndex !== -1) { + value = value.substring(0, commentIndex) + } + } + + value = value.trim() + + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) || + (value.startsWith('`') && value.endsWith('`')) + ) { + value = value.slice(1, -1) + } + return { key: potentialKey, value, id: generateRowId() } }, []) From 3334dfeefa9a774f8640a813b2e66e4c6c6baf2a Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 23:06:34 -0800 Subject: [PATCH 13/34] fix(firecrawl): updated output for firecrawl extract (#2333) * fix(firecrawl): fixed optional params for firecrawl * fix(build): fixed firecrawl tools * ack PR comments --- apps/docs/content/docs/en/tools/firecrawl.mdx | 1 - apps/sim/tools/firecrawl/crawl.ts | 5 ++--- apps/sim/tools/firecrawl/extract.ts | 16 ---------------- apps/sim/tools/firecrawl/map.ts | 4 ++-- apps/sim/tools/firecrawl/scrape.ts | 6 +++--- apps/sim/tools/firecrawl/search.ts | 6 ++---- apps/sim/tools/firecrawl/types.ts | 6 ------ 7 files changed, 9 insertions(+), 35 deletions(-) diff --git a/apps/docs/content/docs/en/tools/firecrawl.mdx b/apps/docs/content/docs/en/tools/firecrawl.mdx index 1341b7d727..7c8dadc11b 100644 --- a/apps/docs/content/docs/en/tools/firecrawl.mdx +++ b/apps/docs/content/docs/en/tools/firecrawl.mdx @@ -148,7 +148,6 @@ Extract structured data from entire webpages using natural language prompts and | --------- | ---- | ----------- | | `success` | boolean | Whether the extraction operation was successful | | `data` | object | Extracted structured data according to the schema or prompt | -| `sources` | array | Data sources \(only if showSources is enabled\) | diff --git a/apps/sim/tools/firecrawl/crawl.ts b/apps/sim/tools/firecrawl/crawl.ts index 335ee4c342..f6bd018f86 100644 --- a/apps/sim/tools/firecrawl/crawl.ts +++ b/apps/sim/tools/firecrawl/crawl.ts @@ -65,9 +65,8 @@ export const crawlTool: ToolConfig if (typeof params.allowSubdomains === 'boolean') body.allowSubdomains = params.allowSubdomains if (typeof params.ignoreQueryParameters === 'boolean') body.ignoreQueryParameters = params.ignoreQueryParameters - if (params.delay != null && params.delay !== '') body.delay = Number(params.delay) - if (params.maxConcurrency != null && params.maxConcurrency !== '') - body.maxConcurrency = Number(params.maxConcurrency) + if (params.delay) body.delay = Number(params.delay) + if (params.maxConcurrency) body.maxConcurrency = Number(params.maxConcurrency) if (params.excludePaths) body.excludePaths = params.excludePaths if (params.includePaths) body.includePaths = params.includePaths if (params.webhook) body.webhook = params.webhook diff --git a/apps/sim/tools/firecrawl/extract.ts b/apps/sim/tools/firecrawl/extract.ts index 0f79987048..a92242963a 100644 --- a/apps/sim/tools/firecrawl/extract.ts +++ b/apps/sim/tools/firecrawl/extract.ts @@ -162,7 +162,6 @@ export const extractTool: ToolConfig = { jobId, success: true, data: extractData.data || {}, - warning: extractData.warning, } return result } @@ -210,20 +209,5 @@ export const extractTool: ToolConfig = { type: 'object', description: 'Extracted structured data according to the schema or prompt', }, - sources: { - type: 'array', - description: 'Data sources (only if showSources is enabled)', - items: { - type: 'object', - properties: { - url: { type: 'string', description: 'Source URL' }, - title: { type: 'string', description: 'Source title' }, - }, - }, - }, - warning: { - type: 'string', - description: 'Warning messages from the extraction operation', - }, }, } diff --git a/apps/sim/tools/firecrawl/map.ts b/apps/sim/tools/firecrawl/map.ts index 033e2861ed..2ddd82a434 100644 --- a/apps/sim/tools/firecrawl/map.ts +++ b/apps/sim/tools/firecrawl/map.ts @@ -83,8 +83,8 @@ export const mapTool: ToolConfig = { body.includeSubdomains = params.includeSubdomains if (typeof params.ignoreQueryParameters === 'boolean') body.ignoreQueryParameters = params.ignoreQueryParameters - if (params.limit != null && params.limit !== '') body.limit = Number(params.limit) - if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (params.limit) body.limit = Number(params.limit) + if (params.timeout) body.timeout = Number(params.timeout) if (params.location) body.location = params.location return body diff --git a/apps/sim/tools/firecrawl/scrape.ts b/apps/sim/tools/firecrawl/scrape.ts index 18814132fb..58cb01027b 100644 --- a/apps/sim/tools/firecrawl/scrape.ts +++ b/apps/sim/tools/firecrawl/scrape.ts @@ -45,13 +45,13 @@ export const scrapeTool: ToolConfig = { if (typeof params.onlyMainContent === 'boolean') body.onlyMainContent = params.onlyMainContent if (params.includeTags) body.includeTags = params.includeTags if (params.excludeTags) body.excludeTags = params.excludeTags - if (params.maxAge != null && params.maxAge !== '') body.maxAge = Number(params.maxAge) + if (params.maxAge) body.maxAge = Number(params.maxAge) if (params.headers) body.headers = params.headers - if (params.waitFor != null && params.waitFor !== '') body.waitFor = Number(params.waitFor) + if (params.waitFor) body.waitFor = Number(params.waitFor) if (typeof params.mobile === 'boolean') body.mobile = params.mobile if (typeof params.skipTlsVerification === 'boolean') body.skipTlsVerification = params.skipTlsVerification - if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (params.timeout) body.timeout = Number(params.timeout) if (params.parsers) body.parsers = params.parsers if (params.actions) body.actions = params.actions if (params.location) body.location = params.location diff --git a/apps/sim/tools/firecrawl/search.ts b/apps/sim/tools/firecrawl/search.ts index bf7b112e7b..1b5a1aa226 100644 --- a/apps/sim/tools/firecrawl/search.ts +++ b/apps/sim/tools/firecrawl/search.ts @@ -35,13 +35,13 @@ export const searchTool: ToolConfig = { } // Add optional parameters if provided (truthy check filters empty strings, null, undefined) - if (params.limit != null && params.limit !== '') body.limit = Number(params.limit) + if (params.limit) body.limit = Number(params.limit) if (params.sources) body.sources = params.sources if (params.categories) body.categories = params.categories if (params.tbs) body.tbs = params.tbs if (params.location) body.location = params.location if (params.country) body.country = params.country - if (params.timeout != null && params.timeout !== '') body.timeout = Number(params.timeout) + if (params.timeout) body.timeout = Number(params.timeout) if (typeof params.ignoreInvalidURLs === 'boolean') body.ignoreInvalidURLs = params.ignoreInvalidURLs if (params.scrapeOptions) body.scrapeOptions = params.scrapeOptions @@ -57,7 +57,6 @@ export const searchTool: ToolConfig = { success: true, output: { data: data.data, - warning: data.warning, }, } }, @@ -81,6 +80,5 @@ export const searchTool: ToolConfig = { }, }, }, - warning: { type: 'string', description: 'Warning messages from the search operation' }, }, } diff --git a/apps/sim/tools/firecrawl/types.ts b/apps/sim/tools/firecrawl/types.ts index cf978ddbd5..84810255b9 100644 --- a/apps/sim/tools/firecrawl/types.ts +++ b/apps/sim/tools/firecrawl/types.ts @@ -163,7 +163,6 @@ export interface SearchResponse extends ToolResponse { error?: string } }> - warning?: string } } @@ -198,11 +197,6 @@ export interface ExtractResponse extends ToolResponse { jobId: string success: boolean data: Record - sources?: Array<{ - url: string - title?: string - }> - warning?: string } } From 045475b9fe2fd9fd17a5ae674d6d712132545061 Mon Sep 17 00:00:00 2001 From: Waleed Date: Thu, 11 Dec 2025 23:39:48 -0800 Subject: [PATCH 14/34] feat(i18n): update translations (#2334) Co-authored-by: waleedlatif1 --- apps/docs/content/docs/de/tools/firecrawl.mdx | 3 +-- apps/docs/content/docs/es/tools/firecrawl.mdx | 3 +-- apps/docs/content/docs/fr/tools/firecrawl.mdx | 1 - apps/docs/content/docs/ja/tools/firecrawl.mdx | 1 - apps/docs/content/docs/zh/tools/firecrawl.mdx | 1 - apps/docs/i18n.lock | 2 +- 6 files changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/docs/content/docs/de/tools/firecrawl.mdx b/apps/docs/content/docs/de/tools/firecrawl.mdx index f8341136e7..e80f5cbe8d 100644 --- a/apps/docs/content/docs/de/tools/firecrawl.mdx +++ b/apps/docs/content/docs/de/tools/firecrawl.mdx @@ -144,8 +144,7 @@ Extrahieren Sie strukturierte Daten aus vollständigen Webseiten mithilfe von na | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `success` | boolean | Ob der Extraktionsvorgang erfolgreich war | -| `data` | object | Extrahierte strukturierte Daten gemäß dem Schema oder Prompt | -| `sources` | array | Datenquellen \(nur wenn showSources aktiviert ist\) | +| `data` | object | Extrahierte strukturierte Daten gemäß dem Schema oder der Eingabeaufforderung | ## Hinweise diff --git a/apps/docs/content/docs/es/tools/firecrawl.mdx b/apps/docs/content/docs/es/tools/firecrawl.mdx index 38500db4fb..486d73d9ec 100644 --- a/apps/docs/content/docs/es/tools/firecrawl.mdx +++ b/apps/docs/content/docs/es/tools/firecrawl.mdx @@ -144,8 +144,7 @@ Extrae datos estructurados de páginas web completas utilizando instrucciones en | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `success` | boolean | Si la operación de extracción fue exitosa | -| `data` | object | Datos estructurados extraídos según el esquema o prompt | -| `sources` | array | Fuentes de datos \(solo si showSources está habilitado\) | +| `data` | object | Datos estructurados extraídos según el esquema o indicación | ## Notas diff --git a/apps/docs/content/docs/fr/tools/firecrawl.mdx b/apps/docs/content/docs/fr/tools/firecrawl.mdx index 12dcb06027..af64244467 100644 --- a/apps/docs/content/docs/fr/tools/firecrawl.mdx +++ b/apps/docs/content/docs/fr/tools/firecrawl.mdx @@ -145,7 +145,6 @@ Extrayez des données structurées de pages web entières à l'aide d'instructio | --------- | ---- | ----------- | | `success` | boolean | Indique si l'opération d'extraction a réussi | | `data` | object | Données structurées extraites selon le schéma ou l'invite | -| `sources` | array | Sources de données \(uniquement si showSources est activé\) | ## Remarques diff --git a/apps/docs/content/docs/ja/tools/firecrawl.mdx b/apps/docs/content/docs/ja/tools/firecrawl.mdx index 281cc0ceb4..f4cbbd6e65 100644 --- a/apps/docs/content/docs/ja/tools/firecrawl.mdx +++ b/apps/docs/content/docs/ja/tools/firecrawl.mdx @@ -145,7 +145,6 @@ Firecrawlを使用してウェブ上の情報を検索します | --------- | ---- | ----------- | | `success` | boolean | 抽出操作が成功したかどうか | | `data` | object | スキーマまたはプロンプトに従って抽出された構造化データ | -| `sources` | array | データソース(showSourcesが有効な場合のみ) | ## 注意事項 diff --git a/apps/docs/content/docs/zh/tools/firecrawl.mdx b/apps/docs/content/docs/zh/tools/firecrawl.mdx index e1c92a290a..7d6c1f5b0e 100644 --- a/apps/docs/content/docs/zh/tools/firecrawl.mdx +++ b/apps/docs/content/docs/zh/tools/firecrawl.mdx @@ -145,7 +145,6 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | --------- | ---- | ----------- | | `success` | boolean | 提取操作是否成功 | | `data` | object | 根据模式或提示提取的结构化数据 | -| `sources` | array | 数据来源(仅在启用 showSources 时) | ## 注意 diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index 0a862912b2..ab80578646 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -3464,7 +3464,7 @@ checksums: content/37: 371d0e46b4bd2c23f559b8bc112f6955 content/38: 3e7b1f581c8ef51fb3d9b6ecff47deb4 content/39: bcadfc362b69078beee0088e5936c98b - content/40: 8f63ba4785aed72b1840e562ff0d0df7 + content/40: 07994574571bcaeb3b86ce92c46d0527 content/41: b3f310d5ef115bea5a8b75bf25d7ea9a content/42: dc809f5be4a108f769310dd8290c0db4 bda76150deadd23f7803a15b39c4db66: From cd66fa84d192609355f4fa3073ce54278e3214d6 Mon Sep 17 00:00:00 2001 From: Adam Gough <77861281+aadamgough@users.noreply.github.com> Date: Thu, 11 Dec 2025 23:42:10 -0800 Subject: [PATCH 15/34] fix(tools): fixed trello and telegram operations (#2332) * fixed trello output * fixed telegram --------- Co-authored-by: aadamgough --- apps/sim/blocks/blocks/trello.ts | 7 +------ apps/sim/tools/telegram/send_document.ts | 7 ++++++- apps/sim/tools/trello/add_comment.ts | 2 -- apps/sim/tools/trello/create_card.ts | 2 -- apps/sim/tools/trello/get_actions.ts | 2 -- apps/sim/tools/trello/list_cards.ts | 2 -- apps/sim/tools/trello/list_lists.ts | 2 -- apps/sim/tools/trello/update_card.ts | 2 -- 8 files changed, 7 insertions(+), 19 deletions(-) diff --git a/apps/sim/blocks/blocks/trello.ts b/apps/sim/blocks/blocks/trello.ts index d711feeea6..635b533372 100644 --- a/apps/sim/blocks/blocks/trello.ts +++ b/apps/sim/blocks/blocks/trello.ts @@ -381,7 +381,6 @@ export const TrelloBlock: BlockConfig = { text: { type: 'string', description: 'Comment text' }, }, outputs: { - success: { type: 'boolean', description: 'Whether the operation was successful' }, lists: { type: 'array', description: 'Array of list objects (for list_lists operation)', @@ -404,11 +403,7 @@ export const TrelloBlock: BlockConfig = { }, count: { type: 'number', - description: 'Number of items returned (boards, cards, actions)', - }, - error: { - type: 'string', - description: 'Error message if operation failed', + description: 'Number of items returned (lists, cards, actions)', }, }, } diff --git a/apps/sim/tools/telegram/send_document.ts b/apps/sim/tools/telegram/send_document.ts index 5efecf4a98..5eccd82076 100644 --- a/apps/sim/tools/telegram/send_document.ts +++ b/apps/sim/tools/telegram/send_document.ts @@ -48,10 +48,15 @@ export const telegramSendDocumentTool: ToolConfig< 'Content-Type': 'application/json', }), body: (params: TelegramSendDocumentParams) => { + let normalizedFiles: unknown[] | null = null + if (params.files) { + normalizedFiles = Array.isArray(params.files) ? params.files : [params.files] + } + return { botToken: params.botToken, chatId: params.chatId, - files: params.files || null, + files: normalizedFiles, caption: params.caption, } }, diff --git a/apps/sim/tools/trello/add_comment.ts b/apps/sim/tools/trello/add_comment.ts index e84e65ffe8..a0bc6a0159 100644 --- a/apps/sim/tools/trello/add_comment.ts +++ b/apps/sim/tools/trello/add_comment.ts @@ -86,11 +86,9 @@ export const trelloAddCommentTool: ToolConfig Date: Fri, 12 Dec 2025 11:22:57 -0800 Subject: [PATCH 16/34] feat(mcp): added the ability to refresh servers to grab new tools (#2335) * feat(mcp): added the ability to refresh servers to grab new tools * added tests --- apps/sim/app/api/mcp/servers/route.ts | 58 +++++++++++++-- .../settings-modal/components/mcp/mcp.tsx | 43 ++++++++--- apps/sim/hooks/queries/mcp.ts | 64 +++++++++++++++-- apps/sim/lib/mcp/utils.test.ts | 72 +++++++++++++++++++ apps/sim/lib/mcp/utils.ts | 48 +++++++++++++ 5 files changed, 265 insertions(+), 20 deletions(-) create mode 100644 apps/sim/lib/mcp/utils.test.ts diff --git a/apps/sim/app/api/mcp/servers/route.ts b/apps/sim/app/api/mcp/servers/route.ts index 370ddac581..183c5e434d 100644 --- a/apps/sim/app/api/mcp/servers/route.ts +++ b/apps/sim/app/api/mcp/servers/route.ts @@ -7,7 +7,11 @@ import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware' import { mcpService } from '@/lib/mcp/service' import type { McpTransport } from '@/lib/mcp/types' import { validateMcpServerUrl } from '@/lib/mcp/url-validator' -import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils' +import { + createMcpErrorResponse, + createMcpSuccessResponse, + generateMcpServerId, +} from '@/lib/mcp/utils' const logger = createLogger('McpServersAPI') @@ -50,13 +54,20 @@ export const GET = withMcpAuth('read')( /** * POST - Register a new MCP server for the workspace (requires write permission) + * + * Uses deterministic server IDs based on URL hash to ensure that re-adding + * the same server produces the same ID. This prevents "server not found" errors + * when workflows reference the old server ID after delete/re-add cycles. + * + * If a server with the same ID already exists (same URL in same workspace), + * it will be updated instead of creating a duplicate. */ export const POST = withMcpAuth('write')( async (request: NextRequest, { userId, workspaceId, requestId }) => { try { const body = getParsedBody(request) || (await request.json()) - logger.info(`[${requestId}] Registering new MCP server:`, { + logger.info(`[${requestId}] Registering MCP server:`, { name: body.name, transport: body.transport, workspaceId, @@ -82,7 +93,43 @@ export const POST = withMcpAuth('write')( body.url = urlValidation.normalizedUrl } - const serverId = body.id || crypto.randomUUID() + const serverId = body.url ? generateMcpServerId(workspaceId, body.url) : crypto.randomUUID() + + const [existingServer] = await db + .select({ id: mcpServers.id, deletedAt: mcpServers.deletedAt }) + .from(mcpServers) + .where(and(eq(mcpServers.id, serverId), eq(mcpServers.workspaceId, workspaceId))) + .limit(1) + + if (existingServer) { + logger.info( + `[${requestId}] Server with ID ${serverId} already exists, updating instead of creating` + ) + + await db + .update(mcpServers) + .set({ + name: body.name, + description: body.description, + transport: body.transport, + url: body.url, + headers: body.headers || {}, + timeout: body.timeout || 30000, + retries: body.retries || 3, + enabled: body.enabled !== false, + updatedAt: new Date(), + deletedAt: null, + }) + .where(eq(mcpServers.id, serverId)) + + mcpService.clearCache(workspaceId) + + logger.info( + `[${requestId}] Successfully updated MCP server: ${body.name} (ID: ${serverId})` + ) + + return createMcpSuccessResponse({ serverId, updated: true }, 200) + } await db .insert(mcpServers) @@ -105,9 +152,10 @@ export const POST = withMcpAuth('write')( mcpService.clearCache(workspaceId) - logger.info(`[${requestId}] Successfully registered MCP server: ${body.name}`) + logger.info( + `[${requestId}] Successfully registered MCP server: ${body.name} (ID: ${serverId})` + ) - // Track MCP server registration try { const { trackPlatformEvent } = await import('@/lib/core/telemetry') trackPlatformEvent('platform.mcp.server_added', { diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx index 5f1cf24712..92a9b2c332 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx @@ -20,6 +20,7 @@ import { useDeleteMcpServer, useMcpServers, useMcpToolsQuery, + useRefreshMcpServer, } from '@/hooks/queries/mcp' import { useMcpServerTest } from '@/hooks/use-mcp-server-test' import type { InputFieldType, McpServerFormData, McpServerTestResult } from './components' @@ -89,27 +90,24 @@ export function MCP() { } = useMcpToolsQuery(workspaceId) const createServerMutation = useCreateMcpServer() const deleteServerMutation = useDeleteMcpServer() + const refreshServerMutation = useRefreshMcpServer() const { testResult, isTestingConnection, testConnection, clearTestResult } = useMcpServerTest() const urlInputRef = useRef(null) - // Form state const [showAddForm, setShowAddForm] = useState(false) const [formData, setFormData] = useState(DEFAULT_FORM_DATA) const [isAddingServer, setIsAddingServer] = useState(false) - // Search and filtering state const [searchTerm, setSearchTerm] = useState('') const [deletingServers, setDeletingServers] = useState>(new Set()) - // Delete confirmation dialog state const [showDeleteDialog, setShowDeleteDialog] = useState(false) const [serverToDelete, setServerToDelete] = useState<{ id: string; name: string } | null>(null) - // Server details view state const [selectedServerId, setSelectedServerId] = useState(null) + const [refreshStatus, setRefreshStatus] = useState<'idle' | 'refreshing' | 'refreshed'>('idle') - // Environment variable dropdown state const [showEnvVars, setShowEnvVars] = useState(false) const [envSearchTerm, setEnvSearchTerm] = useState('') const [cursorPosition, setCursorPosition] = useState(0) @@ -255,7 +253,6 @@ export function MCP() { workspaceId, } - // Test connection if not already tested if (!testResult) { const result = await testConnection(serverConfig) if (!result.success) return @@ -396,6 +393,25 @@ export function MCP() { setSelectedServerId(null) }, []) + /** + * Refreshes a server's tools by re-discovering them from the MCP server. + */ + const handleRefreshServer = useCallback( + async (serverId: string) => { + try { + setRefreshStatus('refreshing') + await refreshServerMutation.mutateAsync({ workspaceId, serverId }) + logger.info(`Refreshed MCP server: ${serverId}`) + setRefreshStatus('refreshed') + setTimeout(() => setRefreshStatus('idle'), 2000) + } catch (error) { + logger.error('Failed to refresh MCP server:', error) + setRefreshStatus('idle') + } + }, + [refreshServerMutation, workspaceId] + ) + /** * Gets the selected server and its tools for the detail view. */ @@ -412,12 +428,10 @@ export function MCP() { const showEmptyState = !hasServers && !showAddForm const showNoResults = searchTerm.trim() && filteredServers.length === 0 && servers.length > 0 - // Form validation state const isFormValid = formData.name.trim() && formData.url?.trim() const isSubmitDisabled = serversLoading || isAddingServer || !isFormValid const testButtonLabel = getTestButtonLabel(testResult, isTestingConnection) - // Show detail view if a server is selected if (selectedServer) { const { server, tools } = selectedServer const transportLabel = formatTransportLabel(server.transport || 'http') @@ -478,7 +492,18 @@ export function MCP() {
-
+
+ +
+

+ A creator profile is required to publish templates. +

+ +
) : ( ({ diff --git a/apps/sim/blocks/blocks/grafana.ts b/apps/sim/blocks/blocks/grafana.ts index 9b164169f4..5af634fc38 100644 --- a/apps/sim/blocks/blocks/grafana.ts +++ b/apps/sim/blocks/blocks/grafana.ts @@ -298,7 +298,8 @@ export const GrafanaBlock: BlockConfig = { id: 'annotationDashboardUid', title: 'Dashboard UID', type: 'short-input', - placeholder: 'Optional - attach to specific dashboard', + placeholder: 'Enter dashboard UID', + required: true, condition: { field: 'operation', value: ['grafana_create_annotation', 'grafana_list_annotations'], diff --git a/apps/sim/blocks/blocks/video_generator.ts b/apps/sim/blocks/blocks/video_generator.ts index 0e6518be59..86e3576c5e 100644 --- a/apps/sim/blocks/blocks/video_generator.ts +++ b/apps/sim/blocks/blocks/video_generator.ts @@ -169,6 +169,29 @@ export const VideoGeneratorBlock: BlockConfig = { required: false, }, + // Duration selection - Fal.ai (only for Kling and MiniMax models) + { + id: 'duration', + title: 'Duration (seconds)', + type: 'dropdown', + condition: { + field: 'model', + value: [ + 'kling-2.5-turbo-pro', + 'kling-2.1-pro', + 'minimax-hailuo-2.3-pro', + 'minimax-hailuo-2.3-standard', + ], + }, + options: [ + { label: '5', id: '5' }, + { label: '8', id: '8' }, + { label: '10', id: '10' }, + ], + value: () => '5', + required: false, + }, + // Aspect ratio selection - Veo (only 16:9 and 9:16) { id: 'aspectRatio', @@ -213,6 +236,28 @@ export const VideoGeneratorBlock: BlockConfig = { required: false, }, + // Aspect ratio selection - Fal.ai (only for Kling and MiniMax models) + { + id: 'aspectRatio', + title: 'Aspect Ratio', + type: 'dropdown', + condition: { + field: 'model', + value: [ + 'kling-2.5-turbo-pro', + 'kling-2.1-pro', + 'minimax-hailuo-2.3-pro', + 'minimax-hailuo-2.3-standard', + ], + }, + options: [ + { label: '16:9', id: '16:9' }, + { label: '9:16', id: '9:16' }, + ], + value: () => '16:9', + required: false, + }, + // Note: MiniMax aspect ratio is fixed at 16:9 (not configurable) // Note: Runway Gen-4 Turbo outputs at 720p natively (no resolution selector needed) diff --git a/apps/sim/blocks/blocks/zep.ts b/apps/sim/blocks/blocks/zep.ts index 0798986ba1..bd3f43f66a 100644 --- a/apps/sim/blocks/blocks/zep.ts +++ b/apps/sim/blocks/blocks/zep.ts @@ -276,26 +276,26 @@ export const ZepBlock: BlockConfig = { metadata: { type: 'json', description: 'User metadata' }, }, outputs: { + // Thread operations threadId: { type: 'string', description: 'Thread identifier' }, - userId: { type: 'string', description: 'User identifier' }, uuid: { type: 'string', description: 'Internal UUID' }, createdAt: { type: 'string', description: 'Creation timestamp' }, updatedAt: { type: 'string', description: 'Update timestamp' }, threads: { type: 'json', description: 'Array of threads' }, deleted: { type: 'boolean', description: 'Deletion status' }, + // Message operations messages: { type: 'json', description: 'Message data' }, - messageIds: { type: 'json', description: 'Message identifiers' }, - context: { type: 'string', description: 'User context string' }, - facts: { type: 'json', description: 'Extracted facts' }, - entities: { type: 'json', description: 'Extracted entities' }, - summary: { type: 'string', description: 'Conversation summary' }, - batchId: { type: 'string', description: 'Batch operation ID' }, + messageIds: { type: 'json', description: 'Array of added message UUIDs' }, + added: { type: 'boolean', description: 'Whether messages were added successfully' }, + // Context operations + context: { type: 'string', description: 'User context string (summary or basic mode)' }, + // User operations + userId: { type: 'string', description: 'User identifier' }, email: { type: 'string', description: 'User email' }, firstName: { type: 'string', description: 'User first name' }, lastName: { type: 'string', description: 'User last name' }, metadata: { type: 'json', description: 'User metadata' }, - responseCount: { type: 'number', description: 'Number of items in response' }, - totalCount: { type: 'number', description: 'Total number of items available' }, - rowCount: { type: 'number', description: 'Number of rows in response' }, + // Counts + totalCount: { type: 'number', description: 'Total number of items returned' }, }, } diff --git a/apps/sim/tools/grafana/create_annotation.ts b/apps/sim/tools/grafana/create_annotation.ts index e0e846c5d3..6f82235a03 100644 --- a/apps/sim/tools/grafana/create_annotation.ts +++ b/apps/sim/tools/grafana/create_annotation.ts @@ -46,10 +46,9 @@ export const createAnnotationTool: ToolConfig< }, dashboardUid: { type: 'string', - required: false, + required: true, visibility: 'user-or-llm', - description: - 'UID of the dashboard to add the annotation to (optional for global annotations)', + description: 'UID of the dashboard to add the annotation to', }, panelId: { type: 'number', diff --git a/apps/sim/tools/grafana/create_folder.ts b/apps/sim/tools/grafana/create_folder.ts index c4a289c764..08e05e5cc3 100644 --- a/apps/sim/tools/grafana/create_folder.ts +++ b/apps/sim/tools/grafana/create_folder.ts @@ -108,5 +108,45 @@ export const createFolderTool: ToolConfig = { transformResponse: async (response, params) => { const threadId = params.threadId - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, output: { threadId, added: true, + messageIds: [], }, } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, output: { threadId, - context: data.context, + added: true, messageIds: data.message_uuids || [], }, } }, outputs: { - context: { + threadId: { type: 'string', - description: 'Updated context after adding messages', + description: 'The thread ID', + }, + added: { + type: 'boolean', + description: 'Whether messages were added successfully', }, messageIds: { type: 'array', description: 'Array of added message UUIDs', }, - threadId: { - type: 'string', - description: 'The thread ID', - }, }, } diff --git a/apps/sim/tools/zep/add_user.ts b/apps/sim/tools/zep/add_user.ts index 591c0dc43c..97d5281f52 100644 --- a/apps/sim/tools/zep/add_user.ts +++ b/apps/sim/tools/zep/add_user.ts @@ -80,12 +80,12 @@ export const zepAddUserTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, @@ -93,7 +93,7 @@ export const zepAddUserTool: ToolConfig = { } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, diff --git a/apps/sim/tools/zep/create_thread.ts b/apps/sim/tools/zep/create_thread.ts index 6a98d56165..6b33bd82f7 100644 --- a/apps/sim/tools/zep/create_thread.ts +++ b/apps/sim/tools/zep/create_thread.ts @@ -43,12 +43,12 @@ export const zepCreateThreadTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, @@ -56,7 +56,7 @@ export const zepCreateThreadTool: ToolConfig = { } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, diff --git a/apps/sim/tools/zep/get_context.ts b/apps/sim/tools/zep/get_context.ts index 031c3f4c64..609d30a5e2 100644 --- a/apps/sim/tools/zep/get_context.ts +++ b/apps/sim/tools/zep/get_context.ts @@ -53,21 +53,17 @@ export const zepGetContextTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, output: { - context: data.context || data, - facts: data.facts || [], - entities: data.entities || [], - summary: data.summary, + context: data.context, }, } }, @@ -75,19 +71,7 @@ export const zepGetContextTool: ToolConfig = { outputs: { context: { type: 'string', - description: 'The context string (summary or basic)', - }, - facts: { - type: 'array', - description: 'Extracted facts', - }, - entities: { - type: 'array', - description: 'Extracted entities', - }, - summary: { - type: 'string', - description: 'Conversation summary', + description: 'The context string (summary or basic mode)', }, }, } diff --git a/apps/sim/tools/zep/get_messages.ts b/apps/sim/tools/zep/get_messages.ts index 14cf433080..38fca74422 100644 --- a/apps/sim/tools/zep/get_messages.ts +++ b/apps/sim/tools/zep/get_messages.ts @@ -59,13 +59,12 @@ export const zepGetMessagesTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_threads.ts b/apps/sim/tools/zep/get_threads.ts index c6dbc14010..41f9280ddf 100644 --- a/apps/sim/tools/zep/get_threads.ts +++ b/apps/sim/tools/zep/get_threads.ts @@ -61,13 +61,12 @@ export const zepGetThreadsTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_user.ts b/apps/sim/tools/zep/get_user.ts index 2de9346700..b38f1ecff1 100644 --- a/apps/sim/tools/zep/get_user.ts +++ b/apps/sim/tools/zep/get_user.ts @@ -33,13 +33,12 @@ export const zepGetUserTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_user_threads.ts b/apps/sim/tools/zep/get_user_threads.ts index a28d7ae7d2..a9acc97dc5 100644 --- a/apps/sim/tools/zep/get_user_threads.ts +++ b/apps/sim/tools/zep/get_user_threads.ts @@ -43,19 +43,19 @@ export const zepGetUserThreadsTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() + const threads = data.threads || data || [] return { success: true, output: { - threads: data.threads || data || [], - userId: data.user_id, + threads, + totalCount: threads.length, }, } }, @@ -65,9 +65,9 @@ export const zepGetUserThreadsTool: ToolConfig = { type: 'array', description: 'Array of thread objects for this user', }, - userId: { - type: 'string', - description: 'The user ID', + totalCount: { + type: 'number', + description: 'Total number of threads returned', }, }, } diff --git a/apps/sim/tools/zep/types.ts b/apps/sim/tools/zep/types.ts index ebbdcce99a..7d8bfe249e 100644 --- a/apps/sim/tools/zep/types.ts +++ b/apps/sim/tools/zep/types.ts @@ -5,7 +5,6 @@ export interface ZepResponse extends ToolResponse { output: { // Thread operations threadId?: string - userId?: string uuid?: string createdAt?: string updatedAt?: string @@ -17,26 +16,18 @@ export interface ZepResponse extends ToolResponse { messages?: any[] messageIds?: string[] added?: boolean - batchId?: string // Context operations context?: string - facts?: any[] - entities?: any[] - summary?: string // User operations + userId?: string email?: string firstName?: string lastName?: string metadata?: any - // Pagination - responseCount?: number + // Counts totalCount?: number - rowCount?: number - - // Search results (if needed in future) - searchResults?: any[] } } From e359dc2946b12ed5e45a0ec9c95ecf91bd18502a Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 17:08:48 -0800 Subject: [PATCH 24/34] fix(cron): reject CRON requests when CRON secret is not set (#2343) --- apps/sim/app/api/workflows/middleware.ts | 2 +- apps/sim/lib/auth/internal.ts | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/sim/app/api/workflows/middleware.ts b/apps/sim/app/api/workflows/middleware.ts index 5c1b941865..883e02125c 100644 --- a/apps/sim/app/api/workflows/middleware.ts +++ b/apps/sim/app/api/workflows/middleware.ts @@ -42,7 +42,7 @@ export async function validateWorkflowAccess( } const internalSecret = request.headers.get('X-Internal-Secret') - if (internalSecret === env.INTERNAL_API_SECRET) { + if (env.INTERNAL_API_SECRET && internalSecret === env.INTERNAL_API_SECRET) { return { workflow } } diff --git a/apps/sim/lib/auth/internal.ts b/apps/sim/lib/auth/internal.ts index cba5036dc8..cf354fc957 100644 --- a/apps/sim/lib/auth/internal.ts +++ b/apps/sim/lib/auth/internal.ts @@ -69,6 +69,16 @@ export async function verifyInternalToken( * Returns null if authorized, or a NextResponse with error if unauthorized */ export function verifyCronAuth(request: NextRequest, context?: string): NextResponse | null { + if (!env.CRON_SECRET) { + const contextInfo = context ? ` for ${context}` : '' + logger.warn(`CRON endpoint accessed but CRON_SECRET is not configured${contextInfo}`, { + ip: request.headers.get('x-forwarded-for') ?? request.headers.get('x-real-ip') ?? 'unknown', + userAgent: request.headers.get('user-agent') ?? 'unknown', + context, + }) + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const authHeader = request.headers.get('authorization') const expectedAuth = `Bearer ${env.CRON_SECRET}` if (authHeader !== expectedAuth) { From cd7fa688c90d3213315833ba9aef030292300c9c Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 17:11:01 -0800 Subject: [PATCH 25/34] fix(build): fix DB dockerfile (#2344) --- docker/db.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/db.Dockerfile b/docker/db.Dockerfile index d6b824dccd..c9d8b705f8 100644 --- a/docker/db.Dockerfile +++ b/docker/db.Dockerfile @@ -16,7 +16,7 @@ COPY packages/db/package.json ./packages/db/package.json # Install dependencies with cache mount for faster builds RUN --mount=type=cache,id=bun-cache,target=/root/.bun/install/cache \ - bun install --frozen-lockfile --ignore-scripts + bun install --ignore-scripts # ======================================== # Runner Stage: Production Environment From 92db054c5386b52dd677164f4274151c245dc0ac Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 17:50:34 -0800 Subject: [PATCH 26/34] feat(i18n): update translations (#2345) Co-authored-by: waleedlatif1 --- apps/docs/content/docs/de/tools/stagehand.mdx | 74 ++++++++++++------ apps/docs/content/docs/es/tools/stagehand.mdx | 54 ++++++++++--- apps/docs/content/docs/fr/tools/stagehand.mdx | 58 ++++++++++---- apps/docs/content/docs/fr/tools/trello.mdx | 18 ++--- apps/docs/content/docs/ja/tools/stagehand.mdx | 78 +++++++++++++------ apps/docs/content/docs/zh/tools/stagehand.mdx | 52 ++++++++++--- apps/docs/i18n.lock | 44 +++++++---- 7 files changed, 269 insertions(+), 109 deletions(-) diff --git a/apps/docs/content/docs/de/tools/stagehand.mdx b/apps/docs/content/docs/de/tools/stagehand.mdx index 9e9a1d9215..2a1ffd0f31 100644 --- a/apps/docs/content/docs/de/tools/stagehand.mdx +++ b/apps/docs/content/docs/de/tools/stagehand.mdx @@ -1,6 +1,6 @@ --- -title: Stagehand Extract -description: Extract data from websites +title: Stagehand +description: Web-Automatisierung und Datenextraktion --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -11,43 +11,73 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Stagehand](https://stagehand.com) is a tool that allows you to extract structured data from webpages using Browserbase and OpenAI. +[Stagehand](https://stagehand.com) ist ein Tool, das sowohl die Extraktion strukturierter Daten aus Webseiten als auch autonome Web-Automatisierung mittels Browserbase und modernen LLMs (OpenAI oder Anthropic) ermöglicht. -With Stagehand, you can: +Stagehand bietet zwei Hauptfunktionen in Sim: -- **Extract structured data**: Extract structured data from webpages using Browserbase and OpenAI -- **Save data to a database**: Save the extracted data to a database -- **Automate workflows**: Automate workflows to extract data from webpages +- **stagehand_extract**: Extrahiert strukturierte Daten von einer einzelnen Webseite. Sie geben an, was Sie möchten (ein Schema), und die KI ruft die Daten in dieser Form von der Seite ab und analysiert sie. Dies eignet sich am besten zum Extrahieren von Listen, Feldern oder Objekten, wenn Sie genau wissen, welche Informationen Sie benötigen und woher Sie diese bekommen. -In Sim, the Stagehand integration enables your agents to extract structured data from webpages using Browserbase and OpenAI. This allows for powerful automation scenarios such as data extraction, data analysis, and data integration. Your agents can extract structured data from webpages, save the extracted data to a database, and automate workflows to extract data from webpages. This integration bridges the gap between your AI workflows and your data management system, enabling seamless data extraction and integration. By connecting Sim with Stagehand, you can automate data extraction processes, maintain up-to-date information repositories, generate reports, and organize information intelligently - all through your intelligent agents. +- **stagehand_agent**: Führt einen autonomen Web-Agenten aus, der in der Lage ist, mehrstufige Aufgaben zu erledigen, mit Elementen zu interagieren, zwischen Seiten zu navigieren und strukturierte Ergebnisse zurückzugeben. Dies ist viel flexibler: der Agent kann Dinge wie Anmeldungen, Suchen, Ausfüllen von Formularen, Sammeln von Daten aus verschiedenen Quellen durchführen und ein Endergebnis gemäß einem angeforderten Schema ausgeben. + +**Wesentliche Unterschiede:** + +- *stagehand_extract* ist ein schneller “extrahiere diese Daten von dieser Seite” Vorgang. Es funktioniert am besten für direkte, einstufige Extraktionsaufgaben. +- *stagehand_agent* führt komplexe, mehrstufige autonome Aufgaben im Web aus — wie Navigation, Suche oder sogar Transaktionen — und kann Daten dynamisch gemäß Ihren Anweisungen und einem optionalen Schema extrahieren. + +In der Praxis verwenden Sie **stagehand_extract**, wenn Sie wissen, was Sie wollen und woher, und **stagehand_agent**, wenn Sie einen Bot benötigen, der interaktive Arbeitsabläufe durchdenkt und ausführt. + +Durch die Integration von Stagehand können Sim-Agenten die Datenerfassung, -analyse und Workflow-Ausführung im Web automatisieren: Datenbanken aktualisieren, Informationen organisieren und benutzerdefinierte Berichte erstellen — nahtlos und autonom. {/* MANUAL-CONTENT-END */} -## Usage Instructions +## Gebrauchsanweisung -Integrate Stagehand into the workflow. Can extract structured data from webpages. +Integrieren Sie Stagehand in den Workflow. Kann strukturierte Daten aus Webseiten extrahieren oder einen autonomen Agenten ausführen, um Aufgaben zu erledigen. ## Tools ### `stagehand_extract` -Extract structured data from a webpage using Stagehand +Extrahieren Sie strukturierte Daten von einer Webseite mit Stagehand + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `url` | string | Ja | URL der Webseite, aus der Daten extrahiert werden sollen | +| `instruction` | string | Ja | Anweisungen für die Extraktion | +| `provider` | string | Nein | Zu verwendender KI-Anbieter: openai oder anthropic | +| `apiKey` | string | Ja | API-Schlüssel für den ausgewählten Anbieter | +| `schema` | json | Ja | JSON-Schema, das die Struktur der zu extrahierenden Daten definiert | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `data` | object | Extrahierte strukturierte Daten, die dem bereitgestellten Schema entsprechen | + +### `stagehand_agent` + +Führen Sie einen autonomen Web-Agenten aus, um Aufgaben zu erledigen und strukturierte Daten zu extrahieren -#### Input +#### Eingabe -| Parameter | Type | Required | Description | +| Parameter | Typ | Erforderlich | Beschreibung | | --------- | ---- | -------- | ----------- | -| `url` | string | Yes | URL of the webpage to extract data from | -| `instruction` | string | Yes | Instructions for extraction | -| `apiKey` | string | Yes | OpenAI API key for extraction \(required by Stagehand\) | -| `schema` | json | Yes | JSON schema defining the structure of the data to extract | +| `startUrl` | string | Ja | URL der Webseite, auf der der Agent starten soll | +| `task` | string | Ja | Die zu erledigende Aufgabe oder das zu erreichende Ziel auf der Website | +| `variables` | json | Nein | Optionale Variablen, die in der Aufgabe ersetzt werden sollen (Format: \{key: value\}). Referenzierung in der Aufgabe mit %key% | +| `format` | string | Nein | Keine Beschreibung | +| `provider` | string | Nein | Zu verwendender KI-Anbieter: openai oder anthropic | +| `apiKey` | string | Ja | API-Schlüssel für den ausgewählten Anbieter | +| `outputSchema` | json | Nein | Optionales JSON-Schema, das die Struktur der Daten definiert, die der Agent zurückgeben soll | #### Output -| Parameter | Type | Description | +| Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `data` | object | Extracted structured data matching the provided schema | +| `agentResult` | object | Ergebnis der Stagehand-Agent-Ausführung | -## Notes +## Hinweise -- Category: `tools` -- Type: `stagehand` +- Kategorie: `tools` +- Typ: `stagehand` diff --git a/apps/docs/content/docs/es/tools/stagehand.mdx b/apps/docs/content/docs/es/tools/stagehand.mdx index 47bf4efcb2..47b63c3db7 100644 --- a/apps/docs/content/docs/es/tools/stagehand.mdx +++ b/apps/docs/content/docs/es/tools/stagehand.mdx @@ -1,6 +1,6 @@ --- -title: Stagehand Extract -description: Extrae datos de sitios web +title: Stagehand +description: Automatización web y extracción de datos --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -11,34 +11,42 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Stagehand](https://stagehand.com) es una herramienta que te permite extraer datos estructurados de páginas web utilizando Browserbase y OpenAI. +[Stagehand](https://stagehand.com) es una herramienta que permite tanto la extracción de datos estructurados de páginas web como la automatización web autónoma utilizando Browserbase y LLMs modernos (OpenAI o Anthropic). -Con Stagehand, puedes: +Stagehand ofrece dos capacidades principales en Sim: -- **Extraer datos estructurados**: Extraer datos estructurados de páginas web utilizando Browserbase y OpenAI -- **Guardar datos en una base de datos**: Guardar los datos extraídos en una base de datos -- **Automatizar flujos de trabajo**: Automatizar flujos de trabajo para extraer datos de páginas web +- **stagehand_extract**: Extrae datos estructurados de una sola página web. Especificas lo que quieres (un esquema), y la IA recupera y analiza los datos en esa forma desde la página. Esto es mejor para extraer listas, campos u objetos cuando sabes exactamente qué información necesitas y dónde obtenerla. -En Sim, la integración de Stagehand permite a tus agentes extraer datos estructurados de páginas web utilizando Browserbase y OpenAI. Esto permite escenarios de automatización potentes como extracción de datos, análisis de datos e integración de datos. Tus agentes pueden extraer datos estructurados de páginas web, guardar los datos extraídos en una base de datos y automatizar flujos de trabajo para extraer datos de páginas web. Esta integración cierra la brecha entre tus flujos de trabajo de IA y tu sistema de gestión de datos, permitiendo una extracción e integración de datos sin problemas. Al conectar Sim con Stagehand, puedes automatizar procesos de extracción de datos, mantener repositorios de información actualizados, generar informes y organizar información de manera inteligente, todo a través de tus agentes inteligentes. +- **stagehand_agent**: Ejecuta un agente web autónomo capaz de completar tareas de múltiples pasos, interactuar con elementos, navegar entre páginas y devolver resultados estructurados. Esto es mucho más flexible: el agente puede hacer cosas como iniciar sesión, buscar, completar formularios, recopilar datos de múltiples lugares y generar un resultado final según un esquema solicitado. + +**Diferencias clave:** + +- *stagehand_extract* es una operación rápida de “extraer estos datos de esta página”. Funciona mejor para tareas de extracción directas, de un solo paso. +- *stagehand_agent* realiza tareas autónomas complejas de múltiples pasos en la web — como navegación, búsqueda o incluso transacciones — y puede extraer datos dinámicamente según tus instrucciones y un esquema opcional. + +En la práctica, usa **stagehand_extract** cuando sabes qué quieres y dónde, y usa **stagehand_agent** cuando necesitas que un bot piense y ejecute flujos de trabajo interactivos. + +Al integrar Stagehand, los agentes de Sim pueden automatizar la recopilación de datos, el análisis y la ejecución de flujos de trabajo en la web: actualizando bases de datos, organizando información y generando informes personalizados, de manera fluida y autónoma. {/* MANUAL-CONTENT-END */} ## Instrucciones de uso -Integra Stagehand en el flujo de trabajo. Puede extraer datos estructurados de páginas web. Requiere clave API. +Integra Stagehand en el flujo de trabajo. Puede extraer datos estructurados de páginas web o ejecutar un agente autónomo para realizar tareas. ## Herramientas ### `stagehand_extract` -Extrae datos estructurados de una página web utilizando Stagehand +Extraer datos estructurados de una página web usando Stagehand #### Entrada -| Parámetro | Tipo | Requerido | Descripción | +| Parámetro | Tipo | Obligatorio | Descripción | | --------- | ---- | -------- | ----------- | | `url` | string | Sí | URL de la página web de la que extraer datos | | `instruction` | string | Sí | Instrucciones para la extracción | -| `apiKey` | string | Sí | Clave API de OpenAI para la extracción \(requerida por Stagehand\) | +| `provider` | string | No | Proveedor de IA a utilizar: openai o anthropic | +| `apiKey` | string | Sí | Clave API para el proveedor seleccionado | | `schema` | json | Sí | Esquema JSON que define la estructura de los datos a extraer | #### Salida @@ -47,6 +55,28 @@ Extrae datos estructurados de una página web utilizando Stagehand | --------- | ---- | ----------- | | `data` | object | Datos estructurados extraídos que coinciden con el esquema proporcionado | +### `stagehand_agent` + +Ejecutar un agente web autónomo para completar tareas y extraer datos estructurados + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `startUrl` | string | Sí | URL de la página web donde iniciar el agente | +| `task` | string | Sí | La tarea a completar o el objetivo a lograr en el sitio web | +| `variables` | json | No | Variables opcionales para sustituir en la tarea \(formato: \{key: value\}\). Referencia en la tarea usando %key% | +| `format` | string | No | Sin descripción | +| `provider` | string | No | Proveedor de IA a utilizar: openai o anthropic | +| `apiKey` | string | Sí | Clave API para el proveedor seleccionado | +| `outputSchema` | json | No | Esquema JSON opcional que define la estructura de los datos que el agente debe devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `agentResult` | objeto | Resultado de la ejecución del agente Stagehand | + ## Notas - Categoría: `tools` diff --git a/apps/docs/content/docs/fr/tools/stagehand.mdx b/apps/docs/content/docs/fr/tools/stagehand.mdx index 4dc5a7e060..905c35f751 100644 --- a/apps/docs/content/docs/fr/tools/stagehand.mdx +++ b/apps/docs/content/docs/fr/tools/stagehand.mdx @@ -1,6 +1,6 @@ --- -title: Stagehand Extract -description: Extraire des données de sites web +title: Stagehand +description: Automatisation web et extraction de données --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -11,20 +11,27 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Stagehand](https://stagehand.com) est un outil qui vous permet d'extraire des données structurées de pages web en utilisant Browserbase et OpenAI. +[Stagehand](https://stagehand.com) est un outil qui permet à la fois l'extraction de données structurées à partir de pages web et l'automatisation web autonome en utilisant Browserbase et les LLM modernes (OpenAI ou Anthropic). -Avec Stagehand, vous pouvez : +Stagehand offre deux capacités principales dans Sim : -- **Extraire des données structurées** : Extraire des données structurées de pages web en utilisant Browserbase et OpenAI -- **Enregistrer des données dans une base de données** : Sauvegarder les données extraites dans une base de données -- **Automatiser des flux de travail** : Automatiser des flux de travail pour extraire des données de pages web +- **stagehand_extract** : Extrait des données structurées d'une seule page web. Vous spécifiez ce que vous voulez (un schéma), et l'IA récupère et analyse les données dans cette forme à partir de la page. C'est idéal pour extraire des listes, des champs ou des objets lorsque vous savez exactement quelles informations vous avez besoin et où les obtenir. -Dans Sim, l'intégration Stagehand permet à vos agents d'extraire des données structurées de pages web en utilisant Browserbase et OpenAI. Cela permet des scénarios d'automatisation puissants tels que l'extraction de données, l'analyse de données et l'intégration de données. Vos agents peuvent extraire des données structurées de pages web, sauvegarder les données extraites dans une base de données et automatiser des flux de travail pour extraire des données de pages web. Cette intégration comble le fossé entre vos flux de travail IA et votre système de gestion de données, permettant une extraction et une intégration de données transparentes. En connectant Sim avec Stagehand, vous pouvez automatiser les processus d'extraction de données, maintenir des référentiels d'informations à jour, générer des rapports et organiser intelligemment les informations - le tout grâce à vos agents intelligents. +- **stagehand_agent** : Exécute un agent web autonome capable d'accomplir des tâches en plusieurs étapes, d'interagir avec des éléments, de naviguer entre les pages et de renvoyer des résultats structurés. C'est beaucoup plus flexible : l'agent peut faire des choses comme se connecter, rechercher, remplir des formulaires, recueillir des données de plusieurs endroits et produire un résultat final selon un schéma demandé. + +**Différences clés :** + +- *stagehand_extract* est une opération rapide “extraire ces données de cette page”. Il fonctionne mieux pour les tâches d'extraction directes en une seule étape. +- *stagehand_agent* effectue des tâches autonomes complexes en plusieurs étapes sur le web — comme la navigation, la recherche, ou même des transactions — et peut extraire dynamiquement des données selon vos instructions et un schéma optionnel. + +En pratique, utilisez **stagehand_extract** lorsque vous savez ce que vous voulez et où, et utilisez **stagehand_agent** lorsque vous avez besoin d'un bot pour réfléchir et exécuter des flux de travail interactifs. + +En intégrant Stagehand, les agents Sim peuvent automatiser la collecte de données, l'analyse et l'exécution de flux de travail sur le web : mise à jour de bases de données, organisation d'informations et génération de rapports personnalisés — de manière transparente et autonome. {/* MANUAL-CONTENT-END */} ## Instructions d'utilisation -Intégrez Stagehand dans le flux de travail. Peut extraire des données structurées à partir de pages web. Nécessite une clé API. +Intégrez Stagehand dans le flux de travail. Peut extraire des données structurées à partir de pages web ou exécuter un agent autonome pour effectuer des tâches. ## Outils @@ -35,17 +42,40 @@ Extraire des données structurées d'une page web en utilisant Stagehand #### Entrée | Paramètre | Type | Obligatoire | Description | -| --------- | ---- | ---------- | ----------- | -| `url` | string | Oui | URL de la page web à partir de laquelle extraire des données | -| `instruction` | string | Oui | Instructions pour l'extraction | -| `apiKey` | string | Oui | Clé API OpenAI pour l'extraction \(requise par Stagehand\) | +| --------- | ---- | -------- | ----------- | +| `url` | chaîne | Oui | URL de la page web à partir de laquelle extraire les données | +| `instruction` | chaîne | Oui | Instructions pour l'extraction | +| `provider` | chaîne | Non | Fournisseur d'IA à utiliser : openai ou anthropic | +| `apiKey` | chaîne | Oui | Clé API pour le fournisseur sélectionné | | `schema` | json | Oui | Schéma JSON définissant la structure des données à extraire | #### Sortie | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `data` | object | Données structurées extraites correspondant au schéma fourni | +| `data` | objet | Données structurées extraites correspondant au schéma fourni | + +### `stagehand_agent` + +Exécuter un agent web autonome pour accomplir des tâches et extraire des données structurées + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `startUrl` | chaîne | Oui | URL de la page web sur laquelle démarrer l'agent | +| `task` | chaîne | Oui | La tâche à accomplir ou l'objectif à atteindre sur le site web | +| `variables` | json | Non | Variables optionnelles à substituer dans la tâche (format : \{key: value\}). Référence dans la tâche en utilisant %key% | +| `format` | chaîne | Non | Pas de description | +| `provider` | chaîne | Non | Fournisseur d'IA à utiliser : openai ou anthropic | +| `apiKey` | chaîne | Oui | Clé API pour le fournisseur sélectionné | +| `outputSchema` | json | Non | Schéma JSON optionnel définissant la structure des données que l'agent doit renvoyer | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `agentResult` | object | Résultat de l'exécution de l'agent Stagehand | ## Notes diff --git a/apps/docs/content/docs/fr/tools/trello.mdx b/apps/docs/content/docs/fr/tools/trello.mdx index 849f48f1f1..6929893ccf 100644 --- a/apps/docs/content/docs/fr/tools/trello.mdx +++ b/apps/docs/content/docs/fr/tools/trello.mdx @@ -45,8 +45,8 @@ Lister toutes les listes d'un tableau Trello | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `lists` | tableau | Tableau d'objets liste avec id, nom, fermé, pos et idBoard | -| `count` | nombre | Nombre de listes retournées | +| `lists` | array | Tableau d'objets liste avec id, name, closed, pos et idBoard | +| `count` | number | Nombre de listes retournées | ### `trello_list_cards` @@ -63,8 +63,8 @@ Lister toutes les cartes d'un tableau Trello | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `cards` | tableau | Tableau d'objets carte avec id, nom, desc, url, IDs de tableau/liste, étiquettes et date d'échéance | -| `count` | nombre | Nombre de cartes retournées | +| `cards` | array | Tableau d'objets carte avec id, name, desc, url, IDs de tableau/liste, étiquettes et date d'échéance | +| `count` | number | Nombre de cartes retournées | ### `trello_create_card` @@ -86,7 +86,7 @@ Créer une nouvelle carte sur un tableau Trello | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `card` | objet | L'objet carte créé avec id, nom, desc, url et autres propriétés | +| `card` | object | L'objet carte créé avec id, name, desc, url et autres propriétés | ### `trello_update_card` @@ -108,7 +108,7 @@ Mettre à jour une carte existante sur Trello | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `card` | objet | L'objet carte mis à jour avec id, nom, desc, url et autres propriétés | +| `card` | object | L'objet carte mis à jour avec id, name, desc, url et autres propriétés | ### `trello_get_actions` @@ -127,8 +127,8 @@ Obtenir l'activité/les actions d'un tableau ou d'une carte | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `actions` | tableau | Tableau d'objets action avec type, date, membre et données | -| `count` | nombre | Nombre d'actions retournées | +| `actions` | array | Tableau d'objets action avec type, date, member et data | +| `count` | number | Nombre d'actions retournées | ### `trello_add_comment` @@ -145,7 +145,7 @@ Ajouter un commentaire à une carte Trello | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `comment` | objet | L'objet commentaire créé avec id, texte, date et membre créateur | +| `comment` | object | L'objet commentaire créé avec id, text, date et member creator | ## Notes diff --git a/apps/docs/content/docs/ja/tools/stagehand.mdx b/apps/docs/content/docs/ja/tools/stagehand.mdx index 9e9a1d9215..e23b8a2954 100644 --- a/apps/docs/content/docs/ja/tools/stagehand.mdx +++ b/apps/docs/content/docs/ja/tools/stagehand.mdx @@ -1,6 +1,6 @@ --- -title: Stagehand Extract -description: Extract data from websites +title: Stagehand +description: Webの自動化とデータ抽出 --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -11,43 +11,73 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Stagehand](https://stagehand.com) is a tool that allows you to extract structured data from webpages using Browserbase and OpenAI. +[Stagehand](https://stagehand.com)は、BrowserbaseとモダンなLLM(OpenAIまたはAnthropic)を使用して、Webページからの構造化データの抽出と自律的なWeb自動化の両方を可能にするツールです。 -With Stagehand, you can: +StagehandはSimで2つの主要な機能を提供します: -- **Extract structured data**: Extract structured data from webpages using Browserbase and OpenAI -- **Save data to a database**: Save the extracted data to a database -- **Automate workflows**: Automate workflows to extract data from webpages +- **stagehand_extract**: 単一のWebページから構造化データを抽出します。必要なもの(スキーマ)を指定すると、AIがページからその形式でデータを取得して解析します。これは、必要な情報とその取得場所を正確に把握している場合に、リスト、フィールド、またはオブジェクトを抽出するのに最適です。 -In Sim, the Stagehand integration enables your agents to extract structured data from webpages using Browserbase and OpenAI. This allows for powerful automation scenarios such as data extraction, data analysis, and data integration. Your agents can extract structured data from webpages, save the extracted data to a database, and automate workflows to extract data from webpages. This integration bridges the gap between your AI workflows and your data management system, enabling seamless data extraction and integration. By connecting Sim with Stagehand, you can automate data extraction processes, maintain up-to-date information repositories, generate reports, and organize information intelligently - all through your intelligent agents. +- **stagehand_agent**: 複数ステップのタスクを完了し、要素と対話し、ページ間を移動し、構造化された結果を返すことができる自律型Webエージェントを実行します。これははるかに柔軟で、エージェントはログイン、検索、フォーム入力、複数の場所からのデータ収集、要求されたスキーマに従った最終結果の出力などを行うことができます。 + +**主な違い:** + +- *stagehand_extract*は迅速な“このページからこのデータを抽出する”操作です。直接的な一段階の抽出タスクに最適です。 +- *stagehand_agent*はWeb上で複雑な複数ステップの自律的なタスク(ナビゲーション、検索、さらには取引など)を実行し、指示とオプションのスキーマに従って動的にデータを抽出できます。 + +実際には、何が欲しいのかとその場所を知っている場合は**stagehand_extract**を使用し、インタラクティブなワークフローを考え実行するボットが必要な場合は**stagehand_agent**を使用します。 + +Stagehandを統合することで、Simエージェントはデータ収集、分析、Web上でのワークフロー実行を自動化できます:データベースの更新、情報の整理、カスタムレポートの生成を、シームレスかつ自律的に行います。 {/* MANUAL-CONTENT-END */} -## Usage Instructions +## 使用方法 -Integrate Stagehand into the workflow. Can extract structured data from webpages. +Stagehandをワークフローに統合します。ウェブページから構造化データを抽出したり、タスクを実行する自律型エージェントを実行したりできます。 -## Tools +## ツール ### `stagehand_extract` -Extract structured data from a webpage using Stagehand +Stagehandを使用してウェブページから構造化データを抽出する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `url` | string | はい | データを抽出するウェブページのURL | +| `instruction` | string | はい | 抽出のための指示 | +| `provider` | string | いいえ | 使用するAIプロバイダー:openaiまたはanthropic | +| `apiKey` | string | はい | 選択したプロバイダーのAPIキー | +| `schema` | json | はい | 抽出するデータの構造を定義するJSONスキーマ | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `data` | object | 提供されたスキーマに一致する抽出された構造化データ | + +### `stagehand_agent` + +タスクを完了し構造化データを抽出するための自律型ウェブエージェントを実行する -#### Input +#### 入力 -| Parameter | Type | Required | Description | +| パラメータ | 型 | 必須 | 説明 | | --------- | ---- | -------- | ----------- | -| `url` | string | Yes | URL of the webpage to extract data from | -| `instruction` | string | Yes | Instructions for extraction | -| `apiKey` | string | Yes | OpenAI API key for extraction \(required by Stagehand\) | -| `schema` | json | Yes | JSON schema defining the structure of the data to extract | +| `startUrl` | string | はい | エージェントを開始するウェブページのURL | +| `task` | string | はい | ウェブサイトで完了するタスクまたは達成する目標 | +| `variables` | json | いいえ | タスクで置き換えるオプションの変数(形式:\{key: value\})。タスク内で%key%を使用して参照 | +| `format` | string | いいえ | 説明なし | +| `provider` | string | いいえ | 使用するAIプロバイダー:openaiまたはanthropic | +| `apiKey` | string | はい | 選択したプロバイダーのAPIキー | +| `outputSchema` | json | いいえ | エージェントが返すべきデータの構造を定義するオプションのJSONスキーマ | -#### Output +#### 出力 -| Parameter | Type | Description | +| パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `data` | object | Extracted structured data matching the provided schema | +| `agentResult` | object | Stagehandエージェント実行からの結果 | -## Notes +## 注意事項 -- Category: `tools` -- Type: `stagehand` +- カテゴリー: `tools` +- タイプ: `stagehand` diff --git a/apps/docs/content/docs/zh/tools/stagehand.mdx b/apps/docs/content/docs/zh/tools/stagehand.mdx index 3d3f43721e..6f84fc855a 100644 --- a/apps/docs/content/docs/zh/tools/stagehand.mdx +++ b/apps/docs/content/docs/zh/tools/stagehand.mdx @@ -1,6 +1,6 @@ --- -title: Stagehand Extract -description: 从网站提取数据 +title: Stagehand +description: 网页自动化和数据提取 --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -11,20 +11,27 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" /> {/* MANUAL-CONTENT-START:intro */} -[Stagehand](https://stagehand.com) 是一款工具,可通过 Browserbase 和 OpenAI 从网页中提取结构化数据。 +[Stagehand](https://stagehand.com) 是一款工具,可以通过 Browserbase 和现代 LLMs(如 OpenAI 或 Anthropic)实现从网页中提取结构化数据以及自主网页自动化。 -使用 Stagehand,您可以: +Stagehand 在 Sim 中提供了两项主要功能: -- **提取结构化数据**:通过 Browserbase 和 OpenAI 从网页中提取结构化数据 -- **将数据保存到数据库**:将提取的数据保存到数据库中 -- **自动化工作流程**:自动化工作流程以从网页中提取数据 +- **stagehand_extract**:从单个网页中提取结构化数据。您可以指定所需内容(一个模式),AI 会从页面中以该格式检索并解析数据。这非常适合在您明确知道需要什么信息以及从哪里获取时,用于提取列表、字段或对象。 -在 Sim 中,Stagehand 集成使您的代理能够通过 Browserbase 和 OpenAI 从网页中提取结构化数据。这为数据提取、数据分析和数据集成等强大的自动化场景提供了可能。您的代理可以从网页中提取结构化数据,将提取的数据保存到数据库中,并自动化工作流程以提取数据。此集成弥合了 AI 工作流程与数据管理系统之间的差距,实现了无缝的数据提取和集成。通过将 Sim 与 Stagehand 连接,您可以自动化数据提取流程,维护最新的信息库,生成报告,并智能地组织信息——这一切都通过您的智能代理完成。 +- **stagehand_agent**:运行一个自主的网页代理,能够完成多步骤任务,与元素交互,在页面之间导航,并返回结构化结果。这更加灵活:代理可以执行登录、搜索、填写表单、从多个地方收集数据,并根据请求的模式输出最终结果。 + +**关键区别:** + +- *stagehand_extract* 是一个快速的“从这个页面提取这些数据”的操作。它最适合直接的、一步完成的提取任务。 +- *stagehand_agent* 执行复杂的、多步骤的自主网页任务,例如导航、搜索,甚至交易,并可以根据您的指示和可选的模式动态提取数据。 + +在实际应用中,当您知道需要什么以及在哪里时,请使用 **stagehand_extract**;当您需要一个机器人思考并执行交互式工作流程时,请使用 **stagehand_agent**。 + +通过集成 Stagehand,Sim 代理可以在网页上自动化数据收集、分析和工作流程执行:更新数据库、组织信息以及生成自定义报告——无缝且自主地完成。 {/* MANUAL-CONTENT-END */} ## 使用说明 -将 Stagehand 集成到工作流程中。可以从网页中提取结构化数据。需要 API 密钥。 +将 Stagehand 集成到工作流程中。可以从网页中提取结构化数据,或运行自主代理执行任务。 ## 工具 @@ -38,14 +45,37 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | --------- | ---- | -------- | ----------- | | `url` | string | 是 | 要提取数据的网页 URL | | `instruction` | string | 是 | 提取的指令 | -| `apiKey` | string | 是 | 用于提取的 OpenAI API 密钥 \(Stagehand 所需\) | +| `provider` | string | 否 | 要使用的 AI 提供商:openai 或 anthropic | +| `apiKey` | string | 是 | 所选提供商的 API 密钥 | | `schema` | json | 是 | 定义要提取数据结构的 JSON 架构 | #### 输出 | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `data` | object | 提取的与提供的模式匹配的结构化数据 | +| `data` | object | 符合提供架构的提取结构化数据 | + +### `stagehand_agent` + +运行自主网页代理以完成任务并提取结构化数据 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `startUrl` | string | 是 | 启动代理的网页 URL | +| `task` | string | 是 | 在网站上完成的任务或目标 | +| `variables` | json | 否 | 任务中可替换的可选变量(格式:\{key: value\})。在任务中使用 %key% 引用 | +| `format` | string | 否 | 无描述 | +| `provider` | string | 否 | 要使用的 AI 提供商:openai 或 anthropic | +| `apiKey` | string | 是 | 所选提供商的 API 密钥 | +| `outputSchema` | json | 否 | 定义代理应返回数据结构的可选 JSON 架构 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `agentResult` | object | Stagehand 代理执行的结果 | ## 注意事项 diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index 903e93eb3b..f0ee3ef0c3 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -844,25 +844,35 @@ checksums: content/15: b3f310d5ef115bea5a8b75bf25d7ea9a content/16: a367df5277edf27ed08ff11b03279fdd abf533c0ff218cfc4166a55a9bd3a01f: - meta/title: fa81baef9ba5e794e519b71ad8a0bcf2 - meta/description: a6150e728da734390689627af1a2fd34 + meta/title: 01271b85ff001bf1a4a8d1730f570331 + meta/description: 78b809fd1f5ecde25dab06776f6090d6 content/0: 1b031fb0c62c46b177aeed5c3d3f8f80 content/1: fdd8ecb5e550d9ed729ea0445c3c3ad1 - content/2: a0e89f4efd3f7a0474568bceef251e05 - content/3: c96320b1e7271f8b46b18556cf10f680 - content/4: 0cf4d7d650aec185fb41b3e92f507057 - content/5: 3816dfaf26ed3afd7aff9090710024f1 - content/6: 821e6394b0a953e2b0842b04ae8f3105 - content/7: e47a99fb84a6ba46b2f6bf91c26f842b - content/8: 9c8aa3f09c9b2bd50ea4cdff3598ea4e - content/9: 0f2701a070121f0abbbf8cc289652330 - content/10: 18e01e99857573a423da69c5b4127487 - content/11: 371d0e46b4bd2c23f559b8bc112f6955 - content/12: d9f2aa90cdfac53f9a3b09225bb67700 - content/13: bcadfc362b69078beee0088e5936c98b - content/14: cca5bb45df434d1dd843d94eb9ac3f76 - content/15: b3f310d5ef115bea5a8b75bf25d7ea9a - content/16: c5ce52e3a765ca8ed0be639afb2eee7b + content/2: 6f77421e48f3fc5d9d226461657d5955 + content/3: 992b3abebfb89a1ba9ca3498b86079ff + content/4: 80d3d3ff22a583a17280020155880f42 + content/5: 7e97694717a88e22ca342219173d8007 + content/6: 2c10a97e08ea83f66da35433bba4b161 + content/7: cd0d728e5ece860818fd28cb492b7d51 + content/8: a2f4a9e48c0a82a5cf4776abac56f135 + content/9: d8c8b2d9dfb5aac795de26be43a7d9b9 + content/10: 821e6394b0a953e2b0842b04ae8f3105 + content/11: dfc1ee41d6b3e799ee65271d45fbe2a8 + content/12: 9c8aa3f09c9b2bd50ea4cdff3598ea4e + content/13: 0f2701a070121f0abbbf8cc289652330 + content/14: 18e01e99857573a423da69c5b4127487 + content/15: 371d0e46b4bd2c23f559b8bc112f6955 + content/16: b7d7d051b6003de92f09eff59955c4e7 + content/17: bcadfc362b69078beee0088e5936c98b + content/18: cca5bb45df434d1dd843d94eb9ac3f76 + content/19: b09ace13f48c17268148d1602d105999 + content/20: 553d5f0825e9d426b9753e64dd596872 + content/21: 371d0e46b4bd2c23f559b8bc112f6955 + content/22: ea958419fd22c3fbd2f647aae2ddb32a + content/23: bcadfc362b69078beee0088e5936c98b + content/24: 08992483aceab1862eedadd4e0e374d5 + content/25: b3f310d5ef115bea5a8b75bf25d7ea9a + content/26: c5ce52e3a765ca8ed0be639afb2eee7b 14b4bb962f102a4a42dd93498f0cf40c: meta/title: 7b7b808a136ce10b6199c504e81fb902 meta/description: 9b77a5b1561b43c9f30bb06febc6ff6c From d06d2b01e3679ab65f940ec96be4ea9ccc5d69d6 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:55:29 -0800 Subject: [PATCH 27/34] fix(copilot): fix incorrectly sanitizing json state (#2346) * Fix * Fix * Remove dead code * Fix lint --- .../workflows/sanitization/json-sanitizer.ts | 122 +++++------------- 1 file changed, 31 insertions(+), 91 deletions(-) diff --git a/apps/sim/lib/workflows/sanitization/json-sanitizer.ts b/apps/sim/lib/workflows/sanitization/json-sanitizer.ts index 99477ff036..eb062599f0 100644 --- a/apps/sim/lib/workflows/sanitization/json-sanitizer.ts +++ b/apps/sim/lib/workflows/sanitization/json-sanitizer.ts @@ -2,7 +2,6 @@ import type { Edge } from 'reactflow' import { sanitizeWorkflowForSharing } from '@/lib/workflows/credentials/credential-extractor' import type { BlockState, Loop, Parallel, WorkflowState } from '@/stores/workflows/workflow/types' import { generateLoopBlocks, generateParallelBlocks } from '@/stores/workflows/workflow/utils' -import { TRIGGER_PERSISTED_SUBBLOCK_IDS } from '@/triggers/constants' /** * Sanitized workflow state for copilot (removes all UI-specific data) @@ -65,41 +64,6 @@ export interface ExportWorkflowState { } } -/** - * Check if a subblock contains sensitive/secret data - */ -function isSensitiveSubBlock(key: string, subBlock: BlockState['subBlocks'][string]): boolean { - if (TRIGGER_PERSISTED_SUBBLOCK_IDS.includes(key)) { - return false - } - - // Check if it's an OAuth input type - if (subBlock.type === 'oauth-input') { - return true - } - - // Check if the field name suggests it contains sensitive data - const sensitivePattern = /credential|oauth|api[_-]?key|token|secret|auth|password|bearer/i - if (sensitivePattern.test(key)) { - return true - } - - // Check if the value itself looks like a secret (but not environment variable references) - if (typeof subBlock.value === 'string' && subBlock.value.length > 0) { - // Don't sanitize environment variable references like {{VAR_NAME}} - if (subBlock.value.startsWith('{{') && subBlock.value.endsWith('}}')) { - return false - } - - // If it matches sensitive patterns in the value, it's likely a hardcoded secret - if (sensitivePattern.test(subBlock.value)) { - return true - } - } - - return false -} - /** * Sanitize condition blocks by removing UI-specific metadata * Returns cleaned JSON string (not parsed array) @@ -171,9 +135,26 @@ function sanitizeTools(tools: any[]): any[] { } /** - * Sanitize subblocks by removing null values, secrets, and simplifying structure + * Sort object keys recursively for consistent comparison + */ +function sortKeysRecursively(item: any): any { + if (Array.isArray(item)) { + return item.map(sortKeysRecursively) + } + if (item !== null && typeof item === 'object') { + return Object.keys(item) + .sort() + .reduce((result: any, key: string) => { + result[key] = sortKeysRecursively(item[key]) + return result + }, {}) + } + return item +} + +/** + * Sanitize subblocks by removing null values and simplifying structure * Maps each subblock key directly to its value instead of the full object - * Note: responseFormat is kept as an object for better copilot understanding */ function sanitizeSubBlocks( subBlocks: BlockState['subBlocks'] @@ -181,76 +162,35 @@ function sanitizeSubBlocks( const sanitized: Record = {} Object.entries(subBlocks).forEach(([key, subBlock]) => { - // Special handling for responseFormat - process BEFORE null check - // so we can detect when it's added/removed + // Skip null/undefined values + if (subBlock.value === null || subBlock.value === undefined) { + return + } + + // Normalize responseFormat for consistent key ordering (important for training data) if (key === 'responseFormat') { try { - // Handle null/undefined - skip if no value - if (subBlock.value === null || subBlock.value === undefined) { - return - } - let obj = subBlock.value - // Handle string values - parse them first + // Parse JSON string if needed if (typeof subBlock.value === 'string') { const trimmed = subBlock.value.trim() if (!trimmed) { - // Empty string - skip this field return } obj = JSON.parse(trimmed) } - // Handle object values - normalize keys and keep as object for copilot + // Sort keys for consistent comparison if (obj && typeof obj === 'object') { - // Sort keys recursively for consistent comparison - const sortKeys = (item: any): any => { - if (Array.isArray(item)) { - return item.map(sortKeys) - } - if (item !== null && typeof item === 'object') { - return Object.keys(item) - .sort() - .reduce((result: any, key: string) => { - result[key] = sortKeys(item[key]) - return result - }, {}) - } - return item - } - - // Keep as object (not stringified) for better copilot understanding - const normalized = sortKeys(obj) - sanitized[key] = normalized + sanitized[key] = sortKeysRecursively(obj) return } - - // If we get here, obj is not an object (maybe null or primitive) - skip it - return - } catch (error) { - // Invalid JSON - skip this field to avoid crashes - return - } - } - - // Skip null/undefined values for other fields - if (subBlock.value === null || subBlock.value === undefined) { - return - } - - // For sensitive fields, either omit or replace with placeholder - if (isSensitiveSubBlock(key, subBlock)) { - // If it's an environment variable reference, keep it - if ( - typeof subBlock.value === 'string' && - subBlock.value.startsWith('{{') && - subBlock.value.endsWith('}}') - ) { + } catch { + // Invalid JSON - pass through as-is sanitized[key] = subBlock.value + return } - // Otherwise omit the sensitive value entirely - return } // Special handling for condition-input type - clean UI metadata From d27f7c232bef972680c60d66198bc960d41f8e61 Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 18:09:17 -0800 Subject: [PATCH 28/34] fix(next): remove openai and anthropic sdk's from serverExternalPackages (#2349) --- apps/sim/next.config.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index 43a6834f79..e2f3ebaba0 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -80,8 +80,6 @@ const nextConfig: NextConfig = { 'pino-pretty', 'thread-stream', '@browserbasehq/stagehand', - '@anthropic-ai/sdk', - 'openai', ], experimental: { optimizeCss: true, From 132f4bca38b99944ea920ad54fae4ab23e426bce Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Fri, 12 Dec 2025 19:02:08 -0800 Subject: [PATCH 29/34] fix(validation): don't validate disabled blocks (#2348) --- apps/sim/serializer/index.test.ts | 29 +++++++++++++++++++++++++++++ apps/sim/serializer/index.ts | 5 +++++ 2 files changed, 34 insertions(+) diff --git a/apps/sim/serializer/index.test.ts b/apps/sim/serializer/index.test.ts index 158d666fa6..c9fc5b8c9c 100644 --- a/apps/sim/serializer/index.test.ts +++ b/apps/sim/serializer/index.test.ts @@ -589,6 +589,35 @@ describe('Serializer', () => { }).toThrow('Test Jina Block is missing required fields: API Key') }) + it.concurrent('should skip validation for disabled blocks', () => { + const serializer = new Serializer() + + // Create a disabled block with a missing user-only required field + const disabledBlockWithMissingField: any = { + id: 'test-block', + type: 'jina', + name: 'Disabled Jina Block', + position: { x: 0, y: 0 }, + subBlocks: { + url: { value: 'https://example.com' }, + apiKey: { value: null }, // Missing user-only required field + }, + outputs: {}, + enabled: false, // Block is disabled + } + + // Should NOT throw error because the block is disabled + expect(() => { + serializer.serializeWorkflow( + { 'test-block': disabledBlockWithMissingField }, + [], + {}, + undefined, + true + ) + }).not.toThrow() + }) + it.concurrent('should not throw error when all user-only required fields are present', () => { const serializer = new Serializer() diff --git a/apps/sim/serializer/index.ts b/apps/sim/serializer/index.ts index 5450e97e5b..d61c3c344b 100644 --- a/apps/sim/serializer/index.ts +++ b/apps/sim/serializer/index.ts @@ -429,6 +429,11 @@ export class Serializer { blockConfig: any, params: Record ) { + // Skip validation if the block is disabled + if (block.enabled === false) { + return + } + // Skip validation if the block is used as a trigger if ( block.triggerMode === true || From ecf5209e6f4d99732e0cad63f2cca8e43c8390b4 Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com> Date: Fri, 12 Dec 2025 19:22:17 -0800 Subject: [PATCH 30/34] feat(integration): add spotify (#2347) * Add spotify * Finish spotify integration * Fix logo * fix build * Rename tools * Fix docs * Fix lint * Fix imports * ran lint --------- Co-authored-by: waleed --- apps/docs/components/icons.tsx | 12 + apps/docs/components/ui/icon-mapping.ts | 184 +-- apps/docs/content/docs/en/tools/grafana.mdx | 14 +- apps/docs/content/docs/en/tools/meta.json | 1 + apps/docs/content/docs/en/tools/spotify.mdx | 1456 +++++++++++++++++ apps/docs/content/docs/en/tools/zep.mdx | 11 +- apps/sim/blocks/blocks/spotify.ts | 1355 +++++++++++++++ apps/sim/blocks/registry.ts | 2 + apps/sim/components/icons.tsx | 12 + apps/sim/lib/auth/auth.ts | 67 + apps/sim/lib/core/config/env.ts | 2 + .../sim/lib/logs/execution/logging-session.ts | 44 +- apps/sim/lib/oauth/oauth.ts | 52 + apps/sim/package.json | 2 +- apps/sim/tools/registry.ts | 159 ++ apps/sim/tools/spotify/add_playlist_cover.ts | 58 + apps/sim/tools/spotify/add_to_queue.ts | 59 + .../tools/spotify/add_tracks_to_playlist.ts | 71 + apps/sim/tools/spotify/check_following.ts | 64 + .../tools/spotify/check_playlist_followers.ts | 64 + apps/sim/tools/spotify/check_saved_albums.ts | 58 + .../tools/spotify/check_saved_audiobooks.ts | 58 + .../sim/tools/spotify/check_saved_episodes.ts | 58 + apps/sim/tools/spotify/check_saved_shows.ts | 58 + apps/sim/tools/spotify/check_saved_tracks.ts | 71 + apps/sim/tools/spotify/create_playlist.ts | 89 + apps/sim/tools/spotify/follow_artists.ts | 64 + apps/sim/tools/spotify/follow_playlist.ts | 61 + apps/sim/tools/spotify/get_album.ts | 87 + apps/sim/tools/spotify/get_album_tracks.ts | 112 ++ apps/sim/tools/spotify/get_albums.ts | 94 ++ apps/sim/tools/spotify/get_artist.ts | 59 + apps/sim/tools/spotify/get_artist_albums.ts | 116 ++ .../tools/spotify/get_artist_top_tracks.ts | 89 + apps/sim/tools/spotify/get_artists.ts | 82 + apps/sim/tools/spotify/get_audiobook.ts | 95 ++ .../tools/spotify/get_audiobook_chapters.ts | 104 ++ apps/sim/tools/spotify/get_audiobooks.ts | 87 + apps/sim/tools/spotify/get_categories.ts | 82 + apps/sim/tools/spotify/get_current_user.ts | 58 + .../tools/spotify/get_currently_playing.ts | 108 ++ apps/sim/tools/spotify/get_devices.ts | 67 + apps/sim/tools/spotify/get_episode.ts | 94 ++ apps/sim/tools/spotify/get_episodes.ts | 91 ++ .../sim/tools/spotify/get_followed_artists.ts | 100 ++ apps/sim/tools/spotify/get_markets.ts | 47 + apps/sim/tools/spotify/get_new_releases.ts | 88 + apps/sim/tools/spotify/get_playback_state.ts | 103 ++ apps/sim/tools/spotify/get_playlist.ts | 83 + apps/sim/tools/spotify/get_playlist_cover.ts | 66 + apps/sim/tools/spotify/get_playlist_tracks.ts | 113 ++ apps/sim/tools/spotify/get_queue.ts | 85 + apps/sim/tools/spotify/get_recently_played.ts | 102 ++ apps/sim/tools/spotify/get_saved_albums.ts | 106 ++ .../sim/tools/spotify/get_saved_audiobooks.ts | 97 ++ apps/sim/tools/spotify/get_saved_episodes.ts | 106 ++ apps/sim/tools/spotify/get_saved_shows.ts | 96 ++ apps/sim/tools/spotify/get_saved_tracks.ts | 104 ++ apps/sim/tools/spotify/get_show.ts | 89 + apps/sim/tools/spotify/get_show_episodes.ts | 106 ++ apps/sim/tools/spotify/get_shows.ts | 84 + apps/sim/tools/spotify/get_top_artists.ts | 100 ++ apps/sim/tools/spotify/get_top_tracks.ts | 104 ++ apps/sim/tools/spotify/get_track.ts | 81 + apps/sim/tools/spotify/get_tracks.ts | 94 ++ apps/sim/tools/spotify/get_user_playlists.ts | 96 ++ apps/sim/tools/spotify/get_user_profile.ts | 70 + apps/sim/tools/spotify/index.ts | 92 ++ apps/sim/tools/spotify/pause.ts | 52 + apps/sim/tools/spotify/play.ts | 94 ++ apps/sim/tools/spotify/remove_saved_albums.ts | 57 + .../tools/spotify/remove_saved_audiobooks.ts | 57 + .../tools/spotify/remove_saved_episodes.ts | 57 + apps/sim/tools/spotify/remove_saved_shows.ts | 57 + apps/sim/tools/spotify/remove_saved_tracks.ts | 63 + .../spotify/remove_tracks_from_playlist.ts | 65 + .../tools/spotify/reorder_playlist_items.ts | 91 ++ .../tools/spotify/replace_playlist_items.ts | 69 + apps/sim/tools/spotify/save_albums.ts | 55 + apps/sim/tools/spotify/save_audiobooks.ts | 57 + apps/sim/tools/spotify/save_episodes.ts | 57 + apps/sim/tools/spotify/save_shows.ts | 54 + apps/sim/tools/spotify/save_tracks.ts | 48 + apps/sim/tools/spotify/search.ts | 157 ++ apps/sim/tools/spotify/seek.ts | 67 + apps/sim/tools/spotify/set_repeat.ts | 67 + apps/sim/tools/spotify/set_shuffle.ts | 68 + apps/sim/tools/spotify/set_volume.ts | 59 + apps/sim/tools/spotify/skip_next.ts | 52 + apps/sim/tools/spotify/skip_previous.ts | 55 + apps/sim/tools/spotify/transfer_playback.ts | 69 + apps/sim/tools/spotify/types.ts | 1031 ++++++++++++ apps/sim/tools/spotify/unfollow_artists.ts | 64 + apps/sim/tools/spotify/unfollow_playlist.ts | 50 + apps/sim/tools/spotify/update_playlist.ts | 76 + 95 files changed, 10477 insertions(+), 114 deletions(-) create mode 100644 apps/docs/content/docs/en/tools/spotify.mdx create mode 100644 apps/sim/blocks/blocks/spotify.ts create mode 100644 apps/sim/tools/spotify/add_playlist_cover.ts create mode 100644 apps/sim/tools/spotify/add_to_queue.ts create mode 100644 apps/sim/tools/spotify/add_tracks_to_playlist.ts create mode 100644 apps/sim/tools/spotify/check_following.ts create mode 100644 apps/sim/tools/spotify/check_playlist_followers.ts create mode 100644 apps/sim/tools/spotify/check_saved_albums.ts create mode 100644 apps/sim/tools/spotify/check_saved_audiobooks.ts create mode 100644 apps/sim/tools/spotify/check_saved_episodes.ts create mode 100644 apps/sim/tools/spotify/check_saved_shows.ts create mode 100644 apps/sim/tools/spotify/check_saved_tracks.ts create mode 100644 apps/sim/tools/spotify/create_playlist.ts create mode 100644 apps/sim/tools/spotify/follow_artists.ts create mode 100644 apps/sim/tools/spotify/follow_playlist.ts create mode 100644 apps/sim/tools/spotify/get_album.ts create mode 100644 apps/sim/tools/spotify/get_album_tracks.ts create mode 100644 apps/sim/tools/spotify/get_albums.ts create mode 100644 apps/sim/tools/spotify/get_artist.ts create mode 100644 apps/sim/tools/spotify/get_artist_albums.ts create mode 100644 apps/sim/tools/spotify/get_artist_top_tracks.ts create mode 100644 apps/sim/tools/spotify/get_artists.ts create mode 100644 apps/sim/tools/spotify/get_audiobook.ts create mode 100644 apps/sim/tools/spotify/get_audiobook_chapters.ts create mode 100644 apps/sim/tools/spotify/get_audiobooks.ts create mode 100644 apps/sim/tools/spotify/get_categories.ts create mode 100644 apps/sim/tools/spotify/get_current_user.ts create mode 100644 apps/sim/tools/spotify/get_currently_playing.ts create mode 100644 apps/sim/tools/spotify/get_devices.ts create mode 100644 apps/sim/tools/spotify/get_episode.ts create mode 100644 apps/sim/tools/spotify/get_episodes.ts create mode 100644 apps/sim/tools/spotify/get_followed_artists.ts create mode 100644 apps/sim/tools/spotify/get_markets.ts create mode 100644 apps/sim/tools/spotify/get_new_releases.ts create mode 100644 apps/sim/tools/spotify/get_playback_state.ts create mode 100644 apps/sim/tools/spotify/get_playlist.ts create mode 100644 apps/sim/tools/spotify/get_playlist_cover.ts create mode 100644 apps/sim/tools/spotify/get_playlist_tracks.ts create mode 100644 apps/sim/tools/spotify/get_queue.ts create mode 100644 apps/sim/tools/spotify/get_recently_played.ts create mode 100644 apps/sim/tools/spotify/get_saved_albums.ts create mode 100644 apps/sim/tools/spotify/get_saved_audiobooks.ts create mode 100644 apps/sim/tools/spotify/get_saved_episodes.ts create mode 100644 apps/sim/tools/spotify/get_saved_shows.ts create mode 100644 apps/sim/tools/spotify/get_saved_tracks.ts create mode 100644 apps/sim/tools/spotify/get_show.ts create mode 100644 apps/sim/tools/spotify/get_show_episodes.ts create mode 100644 apps/sim/tools/spotify/get_shows.ts create mode 100644 apps/sim/tools/spotify/get_top_artists.ts create mode 100644 apps/sim/tools/spotify/get_top_tracks.ts create mode 100644 apps/sim/tools/spotify/get_track.ts create mode 100644 apps/sim/tools/spotify/get_tracks.ts create mode 100644 apps/sim/tools/spotify/get_user_playlists.ts create mode 100644 apps/sim/tools/spotify/get_user_profile.ts create mode 100644 apps/sim/tools/spotify/index.ts create mode 100644 apps/sim/tools/spotify/pause.ts create mode 100644 apps/sim/tools/spotify/play.ts create mode 100644 apps/sim/tools/spotify/remove_saved_albums.ts create mode 100644 apps/sim/tools/spotify/remove_saved_audiobooks.ts create mode 100644 apps/sim/tools/spotify/remove_saved_episodes.ts create mode 100644 apps/sim/tools/spotify/remove_saved_shows.ts create mode 100644 apps/sim/tools/spotify/remove_saved_tracks.ts create mode 100644 apps/sim/tools/spotify/remove_tracks_from_playlist.ts create mode 100644 apps/sim/tools/spotify/reorder_playlist_items.ts create mode 100644 apps/sim/tools/spotify/replace_playlist_items.ts create mode 100644 apps/sim/tools/spotify/save_albums.ts create mode 100644 apps/sim/tools/spotify/save_audiobooks.ts create mode 100644 apps/sim/tools/spotify/save_episodes.ts create mode 100644 apps/sim/tools/spotify/save_shows.ts create mode 100644 apps/sim/tools/spotify/save_tracks.ts create mode 100644 apps/sim/tools/spotify/search.ts create mode 100644 apps/sim/tools/spotify/seek.ts create mode 100644 apps/sim/tools/spotify/set_repeat.ts create mode 100644 apps/sim/tools/spotify/set_shuffle.ts create mode 100644 apps/sim/tools/spotify/set_volume.ts create mode 100644 apps/sim/tools/spotify/skip_next.ts create mode 100644 apps/sim/tools/spotify/skip_previous.ts create mode 100644 apps/sim/tools/spotify/transfer_playback.ts create mode 100644 apps/sim/tools/spotify/types.ts create mode 100644 apps/sim/tools/spotify/unfollow_artists.ts create mode 100644 apps/sim/tools/spotify/unfollow_playlist.ts create mode 100644 apps/sim/tools/spotify/update_playlist.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index e88000cabe..f9e690a726 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4203,3 +4203,15 @@ export function RssIcon(props: SVGProps) { ) } + +export function SpotifyIcon(props: SVGProps) { + return ( + + + + + ) +} diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 6476bf0735..9771381871 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -89,6 +89,7 @@ import { ShopifyIcon, SlackIcon, SmtpIcon, + SpotifyIcon, SQSIcon, SshIcon, STTIcon, @@ -118,115 +119,116 @@ import { type IconComponent = ComponentType> export const blockTypeToIconMap: Record = { - zoom: ZoomIcon, - zep: ZepIcon, - zendesk: ZendeskIcon, - youtube: YouTubeIcon, - x: xIcon, - wordpress: WordpressIcon, - wikipedia: WikipediaIcon, - whatsapp: WhatsAppIcon, - webflow: WebflowIcon, - wealthbox: WealthboxIcon, - vision: EyeIcon, - video_generator: VideoIcon, - typeform: TypeformIcon, + calendly: CalendlyIcon, + mailchimp: MailchimpIcon, + postgresql: PostgresIcon, twilio_voice: TwilioIcon, - twilio_sms: TwilioIcon, - tts: TTSIcon, - trello: TrelloIcon, + elasticsearch: ElasticsearchIcon, + rds: RDSIcon, translate: TranslateIcon, - thinking: BrainIcon, - telegram: TelegramIcon, + dynamodb: DynamoDBIcon, + wordpress: WordpressIcon, tavily: TavilyIcon, + zendesk: ZendeskIcon, + youtube: YouTubeIcon, supabase: SupabaseIcon, - stt: STTIcon, - stripe: StripeIcon, - stagehand: StagehandIcon, - ssh: SshIcon, - sqs: SQSIcon, - smtp: SmtpIcon, - slack: SlackIcon, + vision: EyeIcon, + zoom: ZoomIcon, + confluence: ConfluenceIcon, + arxiv: ArxivIcon, + webflow: WebflowIcon, + pinecone: PineconeIcon, + apollo: ApolloIcon, + whatsapp: WhatsAppIcon, + typeform: TypeformIcon, + qdrant: QdrantIcon, shopify: ShopifyIcon, - sharepoint: MicrosoftSharepointIcon, - sftp: SftpIcon, + asana: AsanaIcon, + sqs: SQSIcon, + apify: ApifyIcon, + memory: BrainIcon, + gitlab: GitLabIcon, + polymarket: PolymarketIcon, serper: SerperIcon, - sentry: SentryIcon, - sendgrid: SendgridIcon, - search: SearchIcon, + linear: LinearIcon, + exa: ExaAIIcon, + telegram: TelegramIcon, salesforce: SalesforceIcon, - s3: S3Icon, - resend: ResendIcon, - reddit: RedditIcon, - rds: RDSIcon, - qdrant: QdrantIcon, + hubspot: HubspotIcon, + hunter: HunterIOIcon, + linkup: LinkupIcon, + mongodb: MongoDBIcon, + airtable: AirtableIcon, + discord: DiscordIcon, + ahrefs: AhrefsIcon, + neo4j: Neo4jIcon, + tts: TTSIcon, + jina: JinaAIIcon, + google_docs: GoogleDocsIcon, + perplexity: PerplexityIcon, + google_search: GoogleIcon, + x: xIcon, + kalshi: KalshiIcon, + google_calendar: GoogleCalendarIcon, + zep: ZepIcon, posthog: PosthogIcon, - postgresql: PostgresIcon, - polymarket: PolymarketIcon, + grafana: GrafanaIcon, + google_slides: GoogleSlidesIcon, + microsoft_planner: MicrosoftPlannerIcon, + thinking: BrainIcon, pipedrive: PipedriveIcon, - pinecone: PineconeIcon, - perplexity: PerplexityIcon, - parallel_ai: ParallelIcon, - outlook: OutlookIcon, + dropbox: DropboxIcon, + stagehand: StagehandIcon, + google_forms: GoogleFormsIcon, + file: DocumentIcon, + mistral_parse: MistralIcon, + gmail: GmailIcon, openai: OpenAIIcon, + outlook: OutlookIcon, + incidentio: IncidentioIcon, onedrive: MicrosoftOneDriveIcon, + resend: ResendIcon, + google_vault: GoogleVaultIcon, + sharepoint: MicrosoftSharepointIcon, + huggingface: HuggingFaceIcon, + sendgrid: SendgridIcon, + video_generator: VideoIcon, + smtp: SmtpIcon, + google_groups: GoogleGroupsIcon, + mailgun: MailgunIcon, + clay: ClayIcon, + jira: JiraIcon, + search: SearchIcon, + linkedin: LinkedInIcon, + wealthbox: WealthboxIcon, notion: NotionIcon, - neo4j: Neo4jIcon, - mysql: MySQLIcon, - mongodb: MongoDBIcon, - mistral_parse: MistralIcon, + elevenlabs: ElevenLabsIcon, microsoft_teams: MicrosoftTeamsIcon, - microsoft_planner: MicrosoftPlannerIcon, - microsoft_excel: MicrosoftExcelIcon, - memory: BrainIcon, + github: GithubIcon, + sftp: SftpIcon, + ssh: SshIcon, + google_drive: GoogleDriveIcon, + sentry: SentryIcon, + reddit: RedditIcon, + parallel_ai: ParallelIcon, + spotify: SpotifyIcon, + stripe: StripeIcon, + s3: S3Icon, + trello: TrelloIcon, mem0: Mem0Icon, - mailgun: MailgunIcon, - mailchimp: MailchimpIcon, - linkup: LinkupIcon, - linkedin: LinkedInIcon, - linear: LinearIcon, knowledge: PackageSearchIcon, - kalshi: KalshiIcon, - jira: JiraIcon, - jina: JinaAIIcon, intercom: IntercomIcon, - incidentio: IncidentioIcon, - image_generator: ImageIcon, - hunter: HunterIOIcon, - huggingface: HuggingFaceIcon, - hubspot: HubspotIcon, - grafana: GrafanaIcon, - google_vault: GoogleVaultIcon, - google_slides: GoogleSlidesIcon, - google_sheets: GoogleSheetsIcon, - google_groups: GoogleGroupsIcon, - google_forms: GoogleFormsIcon, - google_drive: GoogleDriveIcon, - google_docs: GoogleDocsIcon, - google_calendar: GoogleCalendarIcon, - google_search: GoogleIcon, - gmail: GmailIcon, - gitlab: GitLabIcon, - github: GithubIcon, - firecrawl: FirecrawlIcon, - file: DocumentIcon, - exa: ExaAIIcon, - elevenlabs: ElevenLabsIcon, - elasticsearch: ElasticsearchIcon, - dynamodb: DynamoDBIcon, + twilio_sms: TwilioIcon, duckduckgo: DuckDuckGoIcon, - dropbox: DropboxIcon, - discord: DiscordIcon, + slack: SlackIcon, datadog: DatadogIcon, + microsoft_excel: MicrosoftExcelIcon, + image_generator: ImageIcon, + google_sheets: GoogleSheetsIcon, + wikipedia: WikipediaIcon, cursor: CursorIcon, - confluence: ConfluenceIcon, - clay: ClayIcon, - calendly: CalendlyIcon, + firecrawl: FirecrawlIcon, + mysql: MySQLIcon, browser_use: BrowserUseIcon, - asana: AsanaIcon, - arxiv: ArxivIcon, - apollo: ApolloIcon, - apify: ApifyIcon, - airtable: AirtableIcon, - ahrefs: AhrefsIcon, + stt: STTIcon, } diff --git a/apps/docs/content/docs/en/tools/grafana.mdx b/apps/docs/content/docs/en/tools/grafana.mdx index c79e5c37c8..6654b1c127 100644 --- a/apps/docs/content/docs/en/tools/grafana.mdx +++ b/apps/docs/content/docs/en/tools/grafana.mdx @@ -324,7 +324,7 @@ Create an annotation on a dashboard or as a global annotation | `organizationId` | string | No | Organization ID for multi-org Grafana instances | | `text` | string | Yes | The text content of the annotation | | `tags` | string | No | Comma-separated list of tags | -| `dashboardUid` | string | No | UID of the dashboard to add the annotation to \(optional for global annotations\) | +| `dashboardUid` | string | Yes | UID of the dashboard to add the annotation to | | `panelId` | number | No | ID of the panel to add the annotation to | | `time` | number | No | Start time in epoch milliseconds \(defaults to now\) | | `timeEnd` | number | No | End time in epoch milliseconds \(for range annotations\) | @@ -349,7 +349,7 @@ Query annotations by time range, dashboard, or tags | `organizationId` | string | No | Organization ID for multi-org Grafana instances | | `from` | number | No | Start time in epoch milliseconds | | `to` | number | No | End time in epoch milliseconds | -| `dashboardUid` | string | No | Filter by dashboard UID | +| `dashboardUid` | string | Yes | Dashboard UID to query annotations from | | `panelId` | number | No | Filter by panel ID | | `tags` | string | No | Comma-separated list of tags to filter by | | `type` | string | No | Filter by type \(alert or annotation\) | @@ -490,6 +490,16 @@ Create a new folder in Grafana | `uid` | string | The UID of the created folder | | `title` | string | The title of the created folder | | `url` | string | The URL path to the folder | +| `hasAcl` | boolean | Whether the folder has custom ACL permissions | +| `canSave` | boolean | Whether the current user can save the folder | +| `canEdit` | boolean | Whether the current user can edit the folder | +| `canAdmin` | boolean | Whether the current user has admin rights on the folder | +| `canDelete` | boolean | Whether the current user can delete the folder | +| `createdBy` | string | Username of who created the folder | +| `created` | string | Timestamp when the folder was created | +| `updatedBy` | string | Username of who last updated the folder | +| `updated` | string | Timestamp when the folder was last updated | +| `version` | number | Version number of the folder | diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index b9c653d061..7ca67d7a90 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -85,6 +85,7 @@ "shopify", "slack", "smtp", + "spotify", "sqs", "ssh", "stagehand", diff --git a/apps/docs/content/docs/en/tools/spotify.mdx b/apps/docs/content/docs/en/tools/spotify.mdx new file mode 100644 index 0000000000..1b8cd3b0c7 --- /dev/null +++ b/apps/docs/content/docs/en/tools/spotify.mdx @@ -0,0 +1,1456 @@ +--- +title: Spotify +description: Search music, manage playlists, control playback, and access your library +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Integrate Spotify into your workflow. Search for tracks, albums, artists, and playlists. Manage playlists, access your library, control playback, browse podcasts and audiobooks. + + + +## Tools + +### `spotify_search` + +Search for tracks, albums, artists, or playlists on Spotify. Returns matching results based on the query. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `query` | string | Yes | Search query \(e.g., "Bohemian Rhapsody", "artist:Queen", "genre:rock"\) | +| `type` | string | No | Type of results: track, album, artist, playlist, or comma-separated \(e.g., "track,artist"\) | +| `limit` | number | No | Maximum number of results to return \(1-50\) | +| `offset` | number | No | Index of the first result to return for pagination | +| `market` | string | No | ISO 3166-1 alpha-2 country code to filter results \(e.g., "US", "GB"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | List of matching tracks | + +### `spotify_get_track` + +Get detailed information about a specific track on Spotify by its ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | Yes | The Spotify ID of the track | +| `market` | string | No | ISO 3166-1 alpha-2 country code for track availability | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify track ID | +| `name` | string | Track name | +| `artists` | array | List of artists | +| `album` | object | Album information | +| `duration_ms` | number | Track duration in milliseconds | +| `explicit` | boolean | Whether the track has explicit content | +| `popularity` | number | Popularity score \(0-100\) | +| `preview_url` | string | URL to 30-second preview | +| `external_url` | string | Spotify URL | +| `uri` | string | Spotify URI for the track | + +### `spotify_get_tracks` + +Get detailed information about multiple tracks on Spotify by their IDs (up to 50). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Yes | Comma-separated list of Spotify track IDs \(max 50\) | +| `market` | string | No | ISO 3166-1 alpha-2 country code for track availability | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | List of tracks | + +### `spotify_get_album` + +Get detailed information about an album on Spotify by its ID, including track listing. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Yes | The Spotify ID of the album | +| `market` | string | No | ISO 3166-1 alpha-2 country code for track availability | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify album ID | +| `name` | string | Album name | +| `artists` | array | List of artists | +| `album_type` | string | Type of album \(album, single, compilation\) | +| `total_tracks` | number | Total number of tracks | +| `release_date` | string | Release date | +| `label` | string | Record label | +| `popularity` | number | Popularity score \(0-100\) | +| `genres` | array | List of genres | +| `image_url` | string | Album cover image URL | +| `tracks` | array | List of tracks on the album | +| `external_url` | string | Spotify URL | + +### `spotify_get_albums` + +Get details for multiple albums by their IDs. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Yes | Comma-separated album IDs \(max 20\) | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | List of albums | + +### `spotify_get_album_tracks` + +Get the tracks from an album. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Yes | The Spotify album ID | +| `limit` | number | No | Number of tracks to return \(1-50\) | +| `offset` | number | No | Index of first track to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | json | List of tracks | +| `total` | number | Total number of tracks | +| `next` | string | URL for next page | + +### `spotify_get_saved_albums` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of albums to return \(1-50\) | +| `offset` | number | No | Index of first album to return | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | List of saved albums | +| `total` | number | Total saved albums | +| `next` | string | URL for next page | + +### `spotify_save_albums` + +Save albums to the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Yes | Comma-separated album IDs \(max 20\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether albums were saved | + +### `spotify_remove_saved_albums` + +Remove albums from the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Yes | Comma-separated album IDs \(max 20\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether albums were removed | + +### `spotify_check_saved_albums` + +Check if albums are saved in library. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Yes | Comma-separated album IDs \(max 20\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each album | + +### `spotify_get_artist` + +Get detailed information about an artist on Spotify by their ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Yes | The Spotify ID of the artist | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify artist ID | +| `name` | string | Artist name | +| `genres` | array | List of genres associated with the artist | +| `popularity` | number | Popularity score \(0-100\) | +| `followers` | number | Number of followers | +| `image_url` | string | Artist image URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_artists` + +Get details for multiple artists by their IDs. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Yes | Comma-separated artist IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `artists` | json | List of artists | + +### `spotify_get_artist_albums` + +Get albums by an artist on Spotify. Can filter by album type. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Yes | The Spotify ID of the artist | +| `include_groups` | string | No | Filter by album type: album, single, appears_on, compilation \(comma-separated\) | +| `limit` | number | No | Maximum number of albums to return \(1-50\) | +| `offset` | number | No | Index of the first album to return | +| `market` | string | No | ISO 3166-1 alpha-2 country code | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `albums` | array | Artist | + +### `spotify_get_artist_top_tracks` + +Get the top 10 most popular tracks by an artist on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Yes | The Spotify ID of the artist | +| `market` | string | No | ISO 3166-1 alpha-2 country code \(required for this endpoint\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Artist | + +### `spotify_follow_artists` + +Follow one or more artists. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Yes | Comma-separated artist IDs to follow \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether artists were followed successfully | + +### `spotify_unfollow_artists` + +Unfollow one or more artists. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Yes | Comma-separated artist IDs to unfollow \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether artists were unfollowed successfully | + +### `spotify_get_followed_artists` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of artists to return \(1-50\) | +| `after` | string | No | Cursor for pagination \(last artist ID from previous request\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `artists` | json | List of followed artists | +| `total` | number | Total number of followed artists | +| `next` | string | Cursor for next page | + +### `spotify_check_following` + +Check if the user follows artists or users. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `type` | string | Yes | Type to check: "artist" or "user" | +| `ids` | string | Yes | Comma-separated artist or user IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each ID | + +### `spotify_get_show` + +Get details for a podcast show. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Yes | The Spotify show ID | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Show ID | +| `name` | string | Show name | +| `description` | string | Show description | +| `publisher` | string | Publisher name | +| `total_episodes` | number | Total episodes | +| `explicit` | boolean | Contains explicit content | +| `languages` | json | Languages | +| `image_url` | string | Cover image URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_shows` + +Get details for multiple podcast shows. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Comma-separated show IDs \(max 50\) | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `shows` | json | List of shows | + +### `spotify_get_show_episodes` + +Get episodes from a podcast show. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Yes | The Spotify show ID | +| `limit` | number | No | Number of episodes to return \(1-50\) | +| `offset` | number | No | Index of first episode to return | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | List of episodes | +| `total` | number | Total episodes | +| `next` | string | URL for next page | + +### `spotify_get_saved_shows` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of shows to return \(1-50\) | +| `offset` | number | No | Index of first show to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `shows` | json | List of saved shows | +| `total` | number | Total saved shows | +| `next` | string | URL for next page | + +### `spotify_save_shows` + +Save podcast shows to the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Comma-separated show IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether shows were saved | + +### `spotify_remove_saved_shows` + +Remove podcast shows from the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Comma-separated show IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether shows were removed | + +### `spotify_check_saved_shows` + +Check if shows are saved in library. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Comma-separated show IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each show | + +### `spotify_get_episode` + +Get details for a podcast episode. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | Yes | The Spotify episode ID | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Episode ID | +| `name` | string | Episode name | +| `description` | string | Episode description | +| `duration_ms` | number | Duration in ms | +| `release_date` | string | Release date | +| `explicit` | boolean | Contains explicit content | +| `show` | json | Parent show info | +| `image_url` | string | Cover image URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_episodes` + +Get details for multiple podcast episodes. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Yes | Comma-separated episode IDs \(max 50\) | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | List of episodes | + +### `spotify_get_saved_episodes` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of episodes to return \(1-50\) | +| `offset` | number | No | Index of first episode to return | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | List of saved episodes | +| `total` | number | Total saved episodes | +| `next` | string | URL for next page | + +### `spotify_save_episodes` + +Save podcast episodes to the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Yes | Comma-separated episode IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether episodes were saved | + +### `spotify_remove_saved_episodes` + +Remove podcast episodes from the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Yes | Comma-separated episode IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether episodes were removed | + +### `spotify_check_saved_episodes` + +Check if episodes are saved in library. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Yes | Comma-separated episode IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each episode | + +### `spotify_get_audiobook` + +Get details for an audiobook. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Yes | The Spotify audiobook ID | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Audiobook ID | +| `name` | string | Audiobook name | +| `authors` | json | Authors | +| `narrators` | json | Narrators | +| `publisher` | string | Publisher | +| `description` | string | Description | +| `total_chapters` | number | Total chapters | +| `languages` | json | Languages | +| `image_url` | string | Cover image URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_audiobooks` + +Get details for multiple audiobooks. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Yes | Comma-separated audiobook IDs \(max 50\) | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `audiobooks` | json | List of audiobooks | + +### `spotify_get_audiobook_chapters` + +Get chapters from an audiobook. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Yes | The Spotify audiobook ID | +| `limit` | number | No | Number of chapters to return \(1-50\) | +| `offset` | number | No | Index of first chapter to return | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `chapters` | json | List of chapters | +| `total` | number | Total chapters | +| `next` | string | URL for next page | + +### `spotify_get_saved_audiobooks` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of audiobooks to return \(1-50\) | +| `offset` | number | No | Index of first audiobook to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `audiobooks` | json | List of saved audiobooks | +| `total` | number | Total saved audiobooks | +| `next` | string | URL for next page | + +### `spotify_save_audiobooks` + +Save audiobooks to the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Yes | Comma-separated audiobook IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether audiobooks were saved | + +### `spotify_remove_saved_audiobooks` + +Remove audiobooks from the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Yes | Comma-separated audiobook IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether audiobooks were removed | + +### `spotify_check_saved_audiobooks` + +Check if audiobooks are saved in library. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Yes | Comma-separated audiobook IDs \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each audiobook | + +### `spotify_get_playlist` + +Get detailed information about a playlist on Spotify by its ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify ID of the playlist | +| `market` | string | No | ISO 3166-1 alpha-2 country code for track availability | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify playlist ID | +| `name` | string | Playlist name | +| `description` | string | Playlist description | +| `public` | boolean | Whether the playlist is public | +| `collaborative` | boolean | Whether the playlist is collaborative | +| `owner` | object | Playlist owner information | +| `image_url` | string | Playlist cover image URL | +| `total_tracks` | number | Total number of tracks | +| `snapshot_id` | string | Playlist snapshot ID for versioning | +| `external_url` | string | Spotify URL | + +### `spotify_get_playlist_tracks` + +Get the tracks in a Spotify playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify ID of the playlist | +| `limit` | number | No | Maximum number of tracks to return \(1-100\) | +| `offset` | number | No | Index of the first track to return | +| `market` | string | No | ISO 3166-1 alpha-2 country code for track availability | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | List of tracks in the playlist | + +### `spotify_get_playlist_cover` + +Get a playlist + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `images` | json | List of cover images | + +### `spotify_get_user_playlists` + +Get the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Maximum number of playlists to return \(1-50\) | +| `offset` | number | No | Index of the first playlist to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `playlists` | array | User | + +### `spotify_create_playlist` + +Create a new playlist for the current user on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `name` | string | Yes | Name for the new playlist | +| `description` | string | No | Description for the playlist | +| `public` | boolean | No | Whether the playlist should be public | +| `collaborative` | boolean | No | Whether the playlist should be collaborative \(requires public to be false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify playlist ID | +| `name` | string | Playlist name | +| `description` | string | Playlist description | +| `public` | boolean | Whether the playlist is public | +| `collaborative` | boolean | Whether collaborative | +| `snapshot_id` | string | Playlist snapshot ID | +| `external_url` | string | Spotify URL | + +### `spotify_update_playlist` + +Update a playlist + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `name` | string | No | New name for the playlist | +| `description` | string | No | New description for the playlist | +| `public` | boolean | No | Whether the playlist should be public | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether update succeeded | + +### `spotify_add_playlist_cover` + +Upload a custom cover image for a playlist. Image must be JPEG and under 256KB. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `imageBase64` | string | Yes | Base64-encoded JPEG image \(max 256KB\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether upload succeeded | + +### `spotify_add_tracks_to_playlist` + +Add one or more tracks to a Spotify playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify ID of the playlist | +| `uris` | string | Yes | Comma-separated Spotify URIs \(e.g., "spotify:track:xxx,spotify:track:yyy"\) | +| `position` | number | No | Position to insert tracks \(0-based\). If omitted, tracks are appended. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | New playlist snapshot ID after modification | + +### `spotify_remove_tracks_from_playlist` + +Remove one or more tracks from a Spotify playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify ID of the playlist | +| `uris` | string | Yes | Comma-separated Spotify URIs to remove \(e.g., "spotify:track:xxx,spotify:track:yyy"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | New playlist snapshot ID after modification | + +### `spotify_reorder_playlist_items` + +Move tracks to a different position in a playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `range_start` | number | Yes | Start index of items to reorder | +| `insert_before` | number | Yes | Index to insert items before | +| `range_length` | number | No | Number of items to reorder | +| `snapshot_id` | string | No | Playlist snapshot ID for concurrency control | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | New playlist snapshot ID | + +### `spotify_replace_playlist_items` + +Replace all items in a playlist with new tracks. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `uris` | string | Yes | Comma-separated Spotify URIs \(max 100\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | New playlist snapshot ID | + +### `spotify_follow_playlist` + +Follow (save) a playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `public` | boolean | No | Whether the playlist will be in public playlists | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether follow succeeded | + +### `spotify_unfollow_playlist` + +Unfollow (unsave) a playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether unfollow succeeded | + +### `spotify_check_playlist_followers` + +Check if users follow a playlist. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Yes | The Spotify playlist ID | +| `userIds` | string | Yes | Comma-separated user IDs to check \(max 5\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of booleans for each user | + +### `spotify_get_current_user` + +Get the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Spotify user ID | +| `display_name` | string | Display name | +| `email` | string | Email address | +| `country` | string | Country code | +| `product` | string | Subscription level \(free, premium\) | +| `followers` | number | Number of followers | +| `image_url` | string | Profile image URL | +| `external_url` | string | Spotify profile URL | + +### `spotify_get_user_profile` + +Get a user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `userId` | string | Yes | The Spotify user ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | User ID | +| `display_name` | string | Display name | +| `followers` | number | Number of followers | +| `image_url` | string | Profile image URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_top_tracks` + +Get the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | No | Time range: short_term \(~4 weeks\), medium_term \(~6 months\), long_term \(years\) | +| `limit` | number | No | Number of tracks to return \(1-50\) | +| `offset` | number | No | Index of the first track to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | User | + +### `spotify_get_top_artists` + +Get the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | No | Time range: short_term \(~4 weeks\), medium_term \(~6 months\), long_term \(years\) | +| `limit` | number | No | Number of artists to return \(1-50\) | +| `offset` | number | No | Index of the first artist to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `artists` | array | User | + +### `spotify_get_saved_tracks` + +Get the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of tracks to return \(1-50\) | +| `offset` | number | No | Index of the first track to return | +| `market` | string | No | ISO 3166-1 alpha-2 country code | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | User | + +### `spotify_save_tracks` + +Save tracks to the current user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Yes | Comma-separated Spotify track IDs to save \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether the tracks were saved successfully | + +### `spotify_remove_saved_tracks` + +Remove tracks from the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Yes | Comma-separated track IDs to remove \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether tracks were removed successfully | + +### `spotify_check_saved_tracks` + +Check if one or more tracks are saved in the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Yes | Comma-separated track IDs to check \(max 50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Array of track IDs with saved status | +| `all_saved` | boolean | Whether all tracks are saved | +| `none_saved` | boolean | Whether no tracks are saved | + +### `spotify_get_recently_played` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Number of tracks to return \(1-50\) | +| `after` | number | No | Unix timestamp in milliseconds. Returns items after this cursor. | +| `before` | number | No | Unix timestamp in milliseconds. Returns items before this cursor. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `items` | array | Recently played tracks | + +### `spotify_get_new_releases` + +Get a list of new album releases featured in Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `country` | string | No | ISO 3166-1 alpha-2 country code \(e.g., "US", "GB"\) | +| `limit` | number | No | Number of releases to return \(1-50\) | +| `offset` | number | No | Index of first release to return | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | List of new releases | +| `total` | number | Total number of new releases | +| `next` | string | URL for next page | + +### `spotify_get_categories` + +Get a list of browse categories used to tag items in Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `country` | string | No | ISO 3166-1 alpha-2 country code \(e.g., "US", "GB"\) | +| `locale` | string | No | Locale code \(e.g., "en_US", "es_MX"\) | +| `limit` | number | No | Number of categories to return \(1-50\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `categories` | json | List of browse categories | +| `total` | number | Total number of categories | + +### `spotify_get_markets` + +Get the list of markets where Spotify is available. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `markets` | json | List of ISO country codes | + +### `spotify_get_playback_state` + +Get the current playback state including device, track, and progress. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `market` | string | No | ISO 3166-1 alpha-2 country code | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Whether playback is active | +| `device` | object | Active device information | +| `progress_ms` | number | Progress in milliseconds | +| `currently_playing_type` | string | Type of content playing | +| `shuffle_state` | boolean | Whether shuffle is enabled | +| `repeat_state` | string | Repeat mode \(off, track, context\) | +| `track` | object | Currently playing track | + +### `spotify_get_currently_playing` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `market` | string | No | ISO country code for market | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Whether playback is active | +| `progress_ms` | number | Current position in track \(ms\) | +| `track` | json | Currently playing track | + +### `spotify_get_devices` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `devices` | array | Available playback devices | + +### `spotify_get_queue` + +Get the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `currently_playing` | json | Currently playing track | +| `queue` | json | Upcoming tracks in queue | + +### `spotify_play` + +Start or resume playback on Spotify. Can play specific tracks, albums, or playlists. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | Device ID to play on. If not provided, plays on active device. | +| `context_uri` | string | No | Spotify URI of album, artist, or playlist to play \(e.g., "spotify:album:xxx"\) | +| `uris` | string | No | Comma-separated track URIs to play \(e.g., "spotify:track:xxx,spotify:track:yyy"\) | +| `offset` | number | No | Position in context to start playing \(0-based index\) | +| `position_ms` | number | No | Position in track to start from \(in milliseconds\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether playback started successfully | + +### `spotify_pause` + +Pause playback on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | Device ID to pause. If not provided, pauses active device. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether playback was paused | + +### `spotify_skip_next` + +Skip to the next track on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | Device ID. If not provided, uses active device. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether skip was successful | + +### `spotify_skip_previous` + +Skip to the previous track on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | Device ID. If not provided, uses active device. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether skip was successful | + +### `spotify_seek` + +Seek to a position in the currently playing track. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `position_ms` | number | Yes | Position in milliseconds to seek to | +| `device_id` | string | No | Device ID to target | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether seek was successful | + +### `spotify_add_to_queue` + +Add a track to the user + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `uri` | string | Yes | Spotify URI of the track to add \(e.g., "spotify:track:xxx"\) | +| `device_id` | string | No | Device ID. If not provided, uses active device. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether track was added to queue | + +### `spotify_set_volume` + +Set the playback volume on Spotify. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `volume_percent` | number | Yes | Volume level \(0 to 100\) | +| `device_id` | string | No | Device ID. If not provided, uses active device. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether volume was set | + +### `spotify_set_repeat` + +Set the repeat mode for playback. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `state` | string | Yes | Repeat mode: "off", "track", or "context" | +| `device_id` | string | No | Device ID to target | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether repeat mode was set successfully | + +### `spotify_set_shuffle` + +Turn shuffle on or off. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `state` | boolean | Yes | true for shuffle on, false for off | +| `device_id` | string | No | Device ID to target | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether shuffle was set successfully | + +### `spotify_transfer_playback` + +Transfer playback to a different device. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Yes | Device ID to transfer playback to | +| `play` | boolean | No | Whether to start playing on the new device | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether transfer was successful | + + + +## Notes + +- Category: `tools` +- Type: `spotify` diff --git a/apps/docs/content/docs/en/tools/zep.mdx b/apps/docs/content/docs/en/tools/zep.mdx index 12b924a71c..4b53ed8f4a 100644 --- a/apps/docs/content/docs/en/tools/zep.mdx +++ b/apps/docs/content/docs/en/tools/zep.mdx @@ -96,10 +96,7 @@ Retrieve user context from a thread with summary or basic mode | Parameter | Type | Description | | --------- | ---- | ----------- | -| `context` | string | The context string \(summary or basic\) | -| `facts` | array | Extracted facts | -| `entities` | array | Extracted entities | -| `summary` | string | Conversation summary | +| `context` | string | The context string \(summary or basic mode\) | ### `zep_get_messages` @@ -139,9 +136,9 @@ Add messages to an existing thread | Parameter | Type | Description | | --------- | ---- | ----------- | -| `context` | string | Updated context after adding messages | -| `messageIds` | array | Array of added message UUIDs | | `threadId` | string | The thread ID | +| `added` | boolean | Whether messages were added successfully | +| `messageIds` | array | Array of added message UUIDs | ### `zep_add_user` @@ -211,7 +208,7 @@ List all conversation threads for a specific user | Parameter | Type | Description | | --------- | ---- | ----------- | | `threads` | array | Array of thread objects for this user | -| `userId` | string | The user ID | +| `totalCount` | number | Total number of threads returned | diff --git a/apps/sim/blocks/blocks/spotify.ts b/apps/sim/blocks/blocks/spotify.ts new file mode 100644 index 0000000000..3987dc1b2c --- /dev/null +++ b/apps/sim/blocks/blocks/spotify.ts @@ -0,0 +1,1355 @@ +import { SpotifyIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' +import type { ToolResponse } from '@/tools/types' + +export const SpotifyBlock: BlockConfig = { + type: 'spotify', + name: 'Spotify', + description: 'Search music, manage playlists, control playback, and access your library', + authMode: AuthMode.OAuth, + longDescription: + 'Integrate Spotify into your workflow. Search for tracks, albums, artists, and playlists. Manage playlists, access your library, control playback, browse podcasts and audiobooks.', + docsLink: 'https://docs.sim.ai/tools/spotify', + category: 'tools', + bgColor: '#000000', + icon: SpotifyIcon, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + // Search & Discovery + { label: 'Search', id: 'spotify_search', group: 'Search & Discovery' }, + // Tracks + { label: 'Get Track', id: 'spotify_get_track', group: 'Tracks' }, + { label: 'Get Multiple Tracks', id: 'spotify_get_tracks', group: 'Tracks' }, + // Albums + { label: 'Get Album', id: 'spotify_get_album', group: 'Albums' }, + { label: 'Get Multiple Albums', id: 'spotify_get_albums', group: 'Albums' }, + { label: 'Get Album Tracks', id: 'spotify_get_album_tracks', group: 'Albums' }, + { label: 'Get Saved Albums', id: 'spotify_get_saved_albums', group: 'Albums' }, + { label: 'Save Albums', id: 'spotify_save_albums', group: 'Albums' }, + { label: 'Remove Saved Albums', id: 'spotify_remove_saved_albums', group: 'Albums' }, + { label: 'Check Saved Albums', id: 'spotify_check_saved_albums', group: 'Albums' }, + // Artists + { label: 'Get Artist', id: 'spotify_get_artist', group: 'Artists' }, + { label: 'Get Multiple Artists', id: 'spotify_get_artists', group: 'Artists' }, + { label: 'Get Artist Albums', id: 'spotify_get_artist_albums', group: 'Artists' }, + { label: 'Get Artist Top Tracks', id: 'spotify_get_artist_top_tracks', group: 'Artists' }, + { label: 'Follow Artists', id: 'spotify_follow_artists', group: 'Artists' }, + { label: 'Unfollow Artists', id: 'spotify_unfollow_artists', group: 'Artists' }, + { label: 'Get Followed Artists', id: 'spotify_get_followed_artists', group: 'Artists' }, + { label: 'Check Following', id: 'spotify_check_following', group: 'Artists' }, + // Shows (Podcasts) + { label: 'Get Show', id: 'spotify_get_show', group: 'Podcasts' }, + { label: 'Get Multiple Shows', id: 'spotify_get_shows', group: 'Podcasts' }, + { label: 'Get Show Episodes', id: 'spotify_get_show_episodes', group: 'Podcasts' }, + { label: 'Get Saved Shows', id: 'spotify_get_saved_shows', group: 'Podcasts' }, + { label: 'Save Shows', id: 'spotify_save_shows', group: 'Podcasts' }, + { label: 'Remove Saved Shows', id: 'spotify_remove_saved_shows', group: 'Podcasts' }, + { label: 'Check Saved Shows', id: 'spotify_check_saved_shows', group: 'Podcasts' }, + // Episodes + { label: 'Get Episode', id: 'spotify_get_episode', group: 'Episodes' }, + { label: 'Get Multiple Episodes', id: 'spotify_get_episodes', group: 'Episodes' }, + { label: 'Get Saved Episodes', id: 'spotify_get_saved_episodes', group: 'Episodes' }, + { label: 'Save Episodes', id: 'spotify_save_episodes', group: 'Episodes' }, + { label: 'Remove Saved Episodes', id: 'spotify_remove_saved_episodes', group: 'Episodes' }, + { label: 'Check Saved Episodes', id: 'spotify_check_saved_episodes', group: 'Episodes' }, + // Audiobooks + { label: 'Get Audiobook', id: 'spotify_get_audiobook', group: 'Audiobooks' }, + { label: 'Get Multiple Audiobooks', id: 'spotify_get_audiobooks', group: 'Audiobooks' }, + { + label: 'Get Audiobook Chapters', + id: 'spotify_get_audiobook_chapters', + group: 'Audiobooks', + }, + { label: 'Get Saved Audiobooks', id: 'spotify_get_saved_audiobooks', group: 'Audiobooks' }, + { label: 'Save Audiobooks', id: 'spotify_save_audiobooks', group: 'Audiobooks' }, + { + label: 'Remove Saved Audiobooks', + id: 'spotify_remove_saved_audiobooks', + group: 'Audiobooks', + }, + { + label: 'Check Saved Audiobooks', + id: 'spotify_check_saved_audiobooks', + group: 'Audiobooks', + }, + // Playlists + { label: 'Get Playlist', id: 'spotify_get_playlist', group: 'Playlists' }, + { label: 'Get Playlist Tracks', id: 'spotify_get_playlist_tracks', group: 'Playlists' }, + { label: 'Get Playlist Cover', id: 'spotify_get_playlist_cover', group: 'Playlists' }, + { label: 'Get My Playlists', id: 'spotify_get_user_playlists', group: 'Playlists' }, + { label: 'Create Playlist', id: 'spotify_create_playlist', group: 'Playlists' }, + { label: 'Update Playlist', id: 'spotify_update_playlist', group: 'Playlists' }, + { label: 'Add Playlist Cover', id: 'spotify_add_playlist_cover', group: 'Playlists' }, + { + label: 'Add Tracks to Playlist', + id: 'spotify_add_tracks_to_playlist', + group: 'Playlists', + }, + { + label: 'Remove Tracks from Playlist', + id: 'spotify_remove_tracks_from_playlist', + group: 'Playlists', + }, + { + label: 'Reorder Playlist Items', + id: 'spotify_reorder_playlist_items', + group: 'Playlists', + }, + { + label: 'Replace Playlist Items', + id: 'spotify_replace_playlist_items', + group: 'Playlists', + }, + { label: 'Follow Playlist', id: 'spotify_follow_playlist', group: 'Playlists' }, + { label: 'Unfollow Playlist', id: 'spotify_unfollow_playlist', group: 'Playlists' }, + { + label: 'Check Playlist Followers', + id: 'spotify_check_playlist_followers', + group: 'Playlists', + }, + // User Profile & Library + { label: 'Get My Profile', id: 'spotify_get_current_user', group: 'User & Library' }, + { label: 'Get User Profile', id: 'spotify_get_user_profile', group: 'User & Library' }, + { label: 'Get My Top Tracks', id: 'spotify_get_top_tracks', group: 'User & Library' }, + { label: 'Get My Top Artists', id: 'spotify_get_top_artists', group: 'User & Library' }, + { label: 'Get Saved Tracks', id: 'spotify_get_saved_tracks', group: 'User & Library' }, + { label: 'Save Tracks', id: 'spotify_save_tracks', group: 'User & Library' }, + { + label: 'Remove Saved Tracks', + id: 'spotify_remove_saved_tracks', + group: 'User & Library', + }, + { label: 'Check Saved Tracks', id: 'spotify_check_saved_tracks', group: 'User & Library' }, + { + label: 'Get Recently Played', + id: 'spotify_get_recently_played', + group: 'User & Library', + }, + // Browse + { label: 'Get New Releases', id: 'spotify_get_new_releases', group: 'Browse' }, + { label: 'Get Categories', id: 'spotify_get_categories', group: 'Browse' }, + { label: 'Get Available Markets', id: 'spotify_get_markets', group: 'Browse' }, + // Player Controls + { label: 'Get Playback State', id: 'spotify_get_playback_state', group: 'Player' }, + { label: 'Get Currently Playing', id: 'spotify_get_currently_playing', group: 'Player' }, + { label: 'Get Devices', id: 'spotify_get_devices', group: 'Player' }, + { label: 'Get Queue', id: 'spotify_get_queue', group: 'Player' }, + { label: 'Play', id: 'spotify_play', group: 'Player' }, + { label: 'Pause', id: 'spotify_pause', group: 'Player' }, + { label: 'Skip to Next', id: 'spotify_skip_next', group: 'Player' }, + { label: 'Skip to Previous', id: 'spotify_skip_previous', group: 'Player' }, + { label: 'Seek', id: 'spotify_seek', group: 'Player' }, + { label: 'Add to Queue', id: 'spotify_add_to_queue', group: 'Player' }, + { label: 'Set Volume', id: 'spotify_set_volume', group: 'Player' }, + { label: 'Set Repeat', id: 'spotify_set_repeat', group: 'Player' }, + { label: 'Set Shuffle', id: 'spotify_set_shuffle', group: 'Player' }, + { label: 'Transfer Playback', id: 'spotify_transfer_playback', group: 'Player' }, + ], + value: () => 'spotify_search', + }, + + // === SEARCH === + { + id: 'query', + title: 'Search Query', + type: 'short-input', + placeholder: 'e.g., "Bohemian Rhapsody", "artist:Queen"', + required: true, + condition: { field: 'operation', value: 'spotify_search' }, + }, + { + id: 'type', + title: 'Search Type', + type: 'dropdown', + options: [ + { label: 'Tracks', id: 'track' }, + { label: 'Albums', id: 'album' }, + { label: 'Artists', id: 'artist' }, + { label: 'Playlists', id: 'playlist' }, + { label: 'Shows', id: 'show' }, + { label: 'Episodes', id: 'episode' }, + { label: 'Audiobooks', id: 'audiobook' }, + { label: 'All', id: 'track,album,artist,playlist' }, + ], + value: () => 'track', + condition: { field: 'operation', value: 'spotify_search' }, + }, + + // === TRACK IDs === + { + id: 'trackId', + title: 'Track ID', + type: 'short-input', + placeholder: 'Spotify track ID', + required: true, + condition: { field: 'operation', value: 'spotify_get_track' }, + }, + { + id: 'trackIds', + title: 'Track IDs', + type: 'short-input', + placeholder: 'Comma-separated track IDs', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_tracks', + 'spotify_save_tracks', + 'spotify_remove_saved_tracks', + 'spotify_check_saved_tracks', + ], + }, + }, + + // === ALBUM ID === + { + id: 'albumId', + title: 'Album ID', + type: 'short-input', + placeholder: 'Spotify album ID', + required: true, + condition: { field: 'operation', value: ['spotify_get_album', 'spotify_get_album_tracks'] }, + }, + { + id: 'albumIds', + title: 'Album IDs', + type: 'short-input', + placeholder: 'Comma-separated album IDs', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_albums', + 'spotify_save_albums', + 'spotify_remove_saved_albums', + 'spotify_check_saved_albums', + ], + }, + }, + + // === ARTIST ID === + { + id: 'artistId', + title: 'Artist ID', + type: 'short-input', + placeholder: 'Spotify artist ID', + required: true, + condition: { + field: 'operation', + value: ['spotify_get_artist', 'spotify_get_artist_albums', 'spotify_get_artist_top_tracks'], + }, + }, + { + id: 'artistIds', + title: 'Artist IDs', + type: 'short-input', + placeholder: 'Comma-separated artist IDs', + required: true, + condition: { + field: 'operation', + value: ['spotify_get_artists', 'spotify_follow_artists', 'spotify_unfollow_artists'], + }, + }, + + // === SHOW IDs === + { + id: 'showId', + title: 'Show ID', + type: 'short-input', + placeholder: 'Spotify show/podcast ID', + required: true, + condition: { field: 'operation', value: ['spotify_get_show', 'spotify_get_show_episodes'] }, + }, + { + id: 'showIds', + title: 'Show IDs', + type: 'short-input', + placeholder: 'Comma-separated show IDs', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_shows', + 'spotify_save_shows', + 'spotify_remove_saved_shows', + 'spotify_check_saved_shows', + ], + }, + }, + + // === EPISODE IDs === + { + id: 'episodeId', + title: 'Episode ID', + type: 'short-input', + placeholder: 'Spotify episode ID', + required: true, + condition: { field: 'operation', value: 'spotify_get_episode' }, + }, + { + id: 'episodeIds', + title: 'Episode IDs', + type: 'short-input', + placeholder: 'Comma-separated episode IDs', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_episodes', + 'spotify_save_episodes', + 'spotify_remove_saved_episodes', + 'spotify_check_saved_episodes', + ], + }, + }, + + // === AUDIOBOOK IDs === + { + id: 'audiobookId', + title: 'Audiobook ID', + type: 'short-input', + placeholder: 'Spotify audiobook ID', + required: true, + condition: { + field: 'operation', + value: ['spotify_get_audiobook', 'spotify_get_audiobook_chapters'], + }, + }, + { + id: 'audiobookIds', + title: 'Audiobook IDs', + type: 'short-input', + placeholder: 'Comma-separated audiobook IDs', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_audiobooks', + 'spotify_save_audiobooks', + 'spotify_remove_saved_audiobooks', + 'spotify_check_saved_audiobooks', + ], + }, + }, + + // === CHECK FOLLOWING === + { + id: 'followType', + title: 'Type', + type: 'dropdown', + options: [ + { label: 'Artist', id: 'artist' }, + { label: 'User', id: 'user' }, + ], + value: () => 'artist', + condition: { field: 'operation', value: 'spotify_check_following' }, + }, + { + id: 'ids', + title: 'IDs to Check', + type: 'short-input', + placeholder: 'Comma-separated artist or user IDs', + required: true, + condition: { field: 'operation', value: 'spotify_check_following' }, + }, + + // === USER ID === + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'Spotify user ID', + required: true, + condition: { field: 'operation', value: 'spotify_get_user_profile' }, + }, + + // === PLAYLIST OPERATIONS === + { + id: 'playlistId', + title: 'Playlist ID', + type: 'short-input', + placeholder: 'Spotify playlist ID', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_get_playlist', + 'spotify_get_playlist_tracks', + 'spotify_get_playlist_cover', + 'spotify_update_playlist', + 'spotify_add_playlist_cover', + 'spotify_add_tracks_to_playlist', + 'spotify_remove_tracks_from_playlist', + 'spotify_reorder_playlist_items', + 'spotify_replace_playlist_items', + 'spotify_follow_playlist', + 'spotify_unfollow_playlist', + 'spotify_check_playlist_followers', + ], + }, + }, + { + id: 'name', + title: 'Playlist Name', + type: 'short-input', + placeholder: 'My Awesome Playlist', + required: true, + condition: { field: 'operation', value: 'spotify_create_playlist' }, + }, + { + id: 'newName', + title: 'New Name', + type: 'short-input', + placeholder: 'New playlist name (optional)', + condition: { field: 'operation', value: 'spotify_update_playlist' }, + }, + { + id: 'description', + title: 'Playlist Description', + type: 'long-input', + placeholder: 'Optional description for the playlist', + condition: { + field: 'operation', + value: ['spotify_create_playlist', 'spotify_update_playlist'], + }, + }, + { + id: 'public', + title: 'Public', + type: 'switch', + defaultValue: true, + condition: { + field: 'operation', + value: ['spotify_create_playlist', 'spotify_update_playlist', 'spotify_follow_playlist'], + }, + }, + + // === CHECK PLAYLIST FOLLOWERS === + { + id: 'userIds', + title: 'User IDs', + type: 'short-input', + placeholder: 'Comma-separated user IDs to check (max 5)', + required: true, + condition: { field: 'operation', value: 'spotify_check_playlist_followers' }, + }, + + // === PLAYLIST COVER === + { + id: 'imageBase64', + title: 'Image (Base64)', + type: 'long-input', + placeholder: 'Base64-encoded JPEG image (max 256KB)', + required: true, + condition: { field: 'operation', value: 'spotify_add_playlist_cover' }, + }, + + // === REORDER PLAYLIST === + { + id: 'range_start', + title: 'Range Start', + type: 'short-input', + placeholder: 'Start index of items to move', + required: true, + condition: { field: 'operation', value: 'spotify_reorder_playlist_items' }, + }, + { + id: 'insert_before', + title: 'Insert Before', + type: 'short-input', + placeholder: 'Index to insert before', + required: true, + condition: { field: 'operation', value: 'spotify_reorder_playlist_items' }, + }, + { + id: 'range_length', + title: 'Range Length', + type: 'short-input', + placeholder: 'Number of items to move (default: 1)', + condition: { field: 'operation', value: 'spotify_reorder_playlist_items' }, + }, + + // === ADD/REMOVE/REPLACE TRACKS FROM PLAYLIST === + { + id: 'uris', + title: 'Track URIs', + type: 'short-input', + placeholder: 'spotify:track:xxx,spotify:track:yyy', + required: true, + condition: { + field: 'operation', + value: [ + 'spotify_add_tracks_to_playlist', + 'spotify_remove_tracks_from_playlist', + 'spotify_replace_playlist_items', + ], + }, + }, + + // === COUNTRY/LOCALE === + { + id: 'country', + title: 'Country', + type: 'short-input', + placeholder: 'ISO country code (e.g., US, GB)', + condition: { + field: 'operation', + value: ['spotify_get_new_releases', 'spotify_get_categories'], + }, + }, + + // === TOP ITEMS TIME RANGE === + { + id: 'time_range', + title: 'Time Range', + type: 'dropdown', + options: [ + { label: 'Last 4 Weeks', id: 'short_term' }, + { label: 'Last 6 Months', id: 'medium_term' }, + { label: 'All Time', id: 'long_term' }, + ], + value: () => 'medium_term', + condition: { + field: 'operation', + value: ['spotify_get_top_tracks', 'spotify_get_top_artists'], + }, + }, + + // === PLAYER CONTROLS === + { + id: 'device_id', + title: 'Device ID', + type: 'short-input', + placeholder: 'Optional - uses active device if not specified', + condition: { + field: 'operation', + value: [ + 'spotify_play', + 'spotify_pause', + 'spotify_skip_next', + 'spotify_skip_previous', + 'spotify_add_to_queue', + 'spotify_set_volume', + 'spotify_seek', + 'spotify_set_repeat', + 'spotify_set_shuffle', + ], + }, + }, + { + id: 'context_uri', + title: 'Context URI', + type: 'short-input', + placeholder: 'spotify:album:xxx or spotify:playlist:yyy', + condition: { field: 'operation', value: 'spotify_play' }, + }, + { + id: 'playUris', + title: 'Track URIs', + type: 'short-input', + placeholder: 'spotify:track:xxx (comma-separated for multiple)', + condition: { field: 'operation', value: 'spotify_play' }, + }, + { + id: 'uri', + title: 'Track URI', + type: 'short-input', + placeholder: 'spotify:track:xxx', + required: true, + condition: { field: 'operation', value: 'spotify_add_to_queue' }, + }, + { + id: 'volume_percent', + title: 'Volume', + type: 'slider', + min: 0, + max: 100, + step: 1, + integer: true, + condition: { field: 'operation', value: 'spotify_set_volume' }, + }, + + // === SEEK === + { + id: 'position_ms', + title: 'Position (ms)', + type: 'short-input', + placeholder: 'Position in milliseconds', + required: true, + condition: { field: 'operation', value: 'spotify_seek' }, + }, + + // === REPEAT === + { + id: 'state', + title: 'Repeat Mode', + type: 'dropdown', + options: [ + { label: 'Off', id: 'off' }, + { label: 'Track', id: 'track' }, + { label: 'Context (Album/Playlist)', id: 'context' }, + ], + value: () => 'off', + condition: { field: 'operation', value: 'spotify_set_repeat' }, + }, + + // === SHUFFLE === + { + id: 'shuffle_state', + title: 'Shuffle', + type: 'switch', + defaultValue: false, + condition: { field: 'operation', value: 'spotify_set_shuffle' }, + }, + + // === TRANSFER PLAYBACK === + { + id: 'target_device_id', + title: 'Target Device ID', + type: 'short-input', + placeholder: 'Device ID to transfer to', + required: true, + condition: { field: 'operation', value: 'spotify_transfer_playback' }, + }, + + // === COMMON: LIMIT === + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: 'Number of results (1-50, default: 20)', + condition: { + field: 'operation', + value: [ + 'spotify_search', + 'spotify_get_album_tracks', + 'spotify_get_saved_albums', + 'spotify_get_artist_albums', + 'spotify_get_playlist_tracks', + 'spotify_get_user_playlists', + 'spotify_get_top_tracks', + 'spotify_get_top_artists', + 'spotify_get_saved_tracks', + 'spotify_get_recently_played', + 'spotify_get_new_releases', + 'spotify_get_categories', + 'spotify_get_followed_artists', + 'spotify_get_show_episodes', + 'spotify_get_saved_shows', + 'spotify_get_saved_episodes', + 'spotify_get_audiobook_chapters', + 'spotify_get_saved_audiobooks', + ], + }, + }, + + // === OAUTH CREDENTIAL === + { + id: 'credential', + title: 'Spotify Account', + type: 'oauth-input', + serviceId: 'spotify', + required: true, + }, + ], + tools: { + access: [ + 'spotify_search', + 'spotify_get_track', + 'spotify_get_tracks', + 'spotify_get_album', + 'spotify_get_albums', + 'spotify_get_album_tracks', + 'spotify_get_saved_albums', + 'spotify_save_albums', + 'spotify_remove_saved_albums', + 'spotify_check_saved_albums', + 'spotify_get_artist', + 'spotify_get_artists', + 'spotify_get_artist_albums', + 'spotify_get_artist_top_tracks', + 'spotify_follow_artists', + 'spotify_unfollow_artists', + 'spotify_get_followed_artists', + 'spotify_check_following', + 'spotify_get_show', + 'spotify_get_shows', + 'spotify_get_show_episodes', + 'spotify_get_saved_shows', + 'spotify_save_shows', + 'spotify_remove_saved_shows', + 'spotify_check_saved_shows', + 'spotify_get_episode', + 'spotify_get_episodes', + 'spotify_get_saved_episodes', + 'spotify_save_episodes', + 'spotify_remove_saved_episodes', + 'spotify_check_saved_episodes', + 'spotify_get_audiobook', + 'spotify_get_audiobooks', + 'spotify_get_audiobook_chapters', + 'spotify_get_saved_audiobooks', + 'spotify_save_audiobooks', + 'spotify_remove_saved_audiobooks', + 'spotify_check_saved_audiobooks', + 'spotify_get_playlist', + 'spotify_get_playlist_tracks', + 'spotify_get_playlist_cover', + 'spotify_get_user_playlists', + 'spotify_create_playlist', + 'spotify_update_playlist', + 'spotify_add_playlist_cover', + 'spotify_add_tracks_to_playlist', + 'spotify_remove_tracks_from_playlist', + 'spotify_reorder_playlist_items', + 'spotify_replace_playlist_items', + 'spotify_follow_playlist', + 'spotify_unfollow_playlist', + 'spotify_check_playlist_followers', + 'spotify_get_current_user', + 'spotify_get_user_profile', + 'spotify_get_top_tracks', + 'spotify_get_top_artists', + 'spotify_get_saved_tracks', + 'spotify_save_tracks', + 'spotify_remove_saved_tracks', + 'spotify_check_saved_tracks', + 'spotify_get_recently_played', + 'spotify_get_new_releases', + 'spotify_get_categories', + 'spotify_get_markets', + 'spotify_get_playback_state', + 'spotify_get_currently_playing', + 'spotify_get_devices', + 'spotify_get_queue', + 'spotify_play', + 'spotify_pause', + 'spotify_skip_next', + 'spotify_skip_previous', + 'spotify_seek', + 'spotify_add_to_queue', + 'spotify_set_volume', + 'spotify_set_repeat', + 'spotify_set_shuffle', + 'spotify_transfer_playback', + ], + config: { + tool: (params) => { + // Convert numeric parameters + if (params.limit) { + params.limit = Number(params.limit) + } + if (params.volume_percent) { + params.volume_percent = Number(params.volume_percent) + } + if (params.range_start) { + params.range_start = Number(params.range_start) + } + if (params.insert_before) { + params.insert_before = Number(params.insert_before) + } + if (params.range_length) { + params.range_length = Number(params.range_length) + } + if (params.position_ms) { + params.position_ms = Number(params.position_ms) + } + // Map followType to type for check_following + if (params.followType) { + params.type = params.followType + } + // Map newName to name for update_playlist + if (params.newName) { + params.name = params.newName + } + // Map playUris to uris for play + if (params.playUris) { + params.uris = params.playUris + } + return params.operation || 'spotify_search' + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + credential: { type: 'string', description: 'Spotify OAuth credential' }, + // Search + query: { type: 'string', description: 'Search query' }, + type: { type: 'string', description: 'Search type' }, + // IDs + trackId: { type: 'string', description: 'Spotify track ID' }, + trackIds: { type: 'string', description: 'Comma-separated track IDs' }, + albumId: { type: 'string', description: 'Spotify album ID' }, + albumIds: { type: 'string', description: 'Comma-separated album IDs' }, + artistId: { type: 'string', description: 'Spotify artist ID' }, + artistIds: { type: 'string', description: 'Comma-separated artist IDs' }, + showId: { type: 'string', description: 'Spotify show ID' }, + showIds: { type: 'string', description: 'Comma-separated show IDs' }, + episodeId: { type: 'string', description: 'Spotify episode ID' }, + episodeIds: { type: 'string', description: 'Comma-separated episode IDs' }, + audiobookId: { type: 'string', description: 'Spotify audiobook ID' }, + audiobookIds: { type: 'string', description: 'Comma-separated audiobook IDs' }, + playlistId: { type: 'string', description: 'Spotify playlist ID' }, + userId: { type: 'string', description: 'Spotify user ID' }, + userIds: { type: 'string', description: 'Comma-separated user IDs' }, + ids: { type: 'string', description: 'Comma-separated IDs' }, + followType: { type: 'string', description: 'Type to check (artist or user)' }, + // Playlist + name: { type: 'string', description: 'Playlist name' }, + newName: { type: 'string', description: 'New playlist name' }, + description: { type: 'string', description: 'Playlist description' }, + public: { type: 'boolean', description: 'Whether playlist is public' }, + imageBase64: { type: 'string', description: 'Base64-encoded JPEG image' }, + range_start: { type: 'number', description: 'Start index for reorder' }, + insert_before: { type: 'number', description: 'Insert before index' }, + range_length: { type: 'number', description: 'Number of items to move' }, + // Track URIs + uris: { type: 'string', description: 'Comma-separated Spotify URIs' }, + playUris: { type: 'string', description: 'Track URIs to play' }, + uri: { type: 'string', description: 'Spotify URI' }, + // Time range + time_range: { type: 'string', description: 'Time range for top items' }, + // Browse + country: { type: 'string', description: 'ISO country code' }, + // Player + device_id: { type: 'string', description: 'Device ID for playback' }, + context_uri: { type: 'string', description: 'Context URI (album, playlist, artist)' }, + volume_percent: { type: 'number', description: 'Volume level (0-100)' }, + position_ms: { type: 'number', description: 'Position in milliseconds' }, + state: { type: 'string', description: 'Repeat mode (off, track, context)' }, + shuffle_state: { type: 'boolean', description: 'Shuffle on/off' }, + target_device_id: { type: 'string', description: 'Target device ID for transfer' }, + // Common + limit: { type: 'number', description: 'Maximum number of results' }, + }, + outputs: { + // === SEARCH OUTPUTS === + tracks: { + type: 'json', + description: 'List of tracks', + condition: { + field: 'operation', + value: [ + 'spotify_search', + 'spotify_get_tracks', + 'spotify_get_album_tracks', + 'spotify_get_playlist_tracks', + 'spotify_get_artist_top_tracks', + 'spotify_get_saved_tracks', + 'spotify_get_top_tracks', + ], + }, + }, + artists: { + type: 'json', + description: 'List of artists', + condition: { + field: 'operation', + value: [ + 'spotify_search', + 'spotify_get_artists', + 'spotify_get_top_artists', + 'spotify_get_followed_artists', + ], + }, + }, + albums: { + type: 'json', + description: 'List of albums', + condition: { + field: 'operation', + value: [ + 'spotify_search', + 'spotify_get_albums', + 'spotify_get_artist_albums', + 'spotify_get_saved_albums', + 'spotify_get_new_releases', + ], + }, + }, + playlists: { + type: 'json', + description: 'List of playlists', + condition: { field: 'operation', value: ['spotify_search', 'spotify_get_user_playlists'] }, + }, + + // === SINGLE ITEM OUTPUTS === + id: { + type: 'string', + description: 'Spotify ID', + condition: { + field: 'operation', + value: [ + 'spotify_get_track', + 'spotify_get_album', + 'spotify_get_artist', + 'spotify_get_playlist', + 'spotify_get_show', + 'spotify_get_episode', + 'spotify_get_audiobook', + 'spotify_get_current_user', + 'spotify_get_user_profile', + 'spotify_create_playlist', + ], + }, + }, + name: { + type: 'string', + description: 'Name', + condition: { + field: 'operation', + value: [ + 'spotify_get_track', + 'spotify_get_album', + 'spotify_get_artist', + 'spotify_get_playlist', + 'spotify_get_show', + 'spotify_get_episode', + 'spotify_get_audiobook', + 'spotify_create_playlist', + ], + }, + }, + uri: { + type: 'string', + description: 'Spotify URI', + condition: { field: 'operation', value: 'spotify_get_track' }, + }, + external_url: { + type: 'string', + description: 'Spotify URL', + condition: { + field: 'operation', + value: [ + 'spotify_get_track', + 'spotify_get_album', + 'spotify_get_artist', + 'spotify_get_playlist', + 'spotify_get_show', + 'spotify_get_episode', + 'spotify_get_audiobook', + 'spotify_get_current_user', + 'spotify_get_user_profile', + 'spotify_create_playlist', + ], + }, + }, + image_url: { + type: 'string', + description: 'Cover/profile image URL', + condition: { + field: 'operation', + value: [ + 'spotify_get_track', + 'spotify_get_album', + 'spotify_get_artist', + 'spotify_get_playlist', + 'spotify_get_show', + 'spotify_get_episode', + 'spotify_get_audiobook', + 'spotify_get_current_user', + 'spotify_get_user_profile', + 'spotify_get_playlist_cover', + ], + }, + }, + popularity: { + type: 'number', + description: 'Popularity score (0-100)', + condition: { + field: 'operation', + value: ['spotify_get_track', 'spotify_get_album', 'spotify_get_artist'], + }, + }, + + // === TRACK OUTPUTS === + album: { + type: 'json', + description: 'Album information', + condition: { field: 'operation', value: 'spotify_get_track' }, + }, + duration_ms: { + type: 'number', + description: 'Duration in milliseconds', + condition: { field: 'operation', value: ['spotify_get_track', 'spotify_get_episode'] }, + }, + explicit: { + type: 'boolean', + description: 'Contains explicit content', + condition: { + field: 'operation', + value: ['spotify_get_track', 'spotify_get_show', 'spotify_get_episode'], + }, + }, + preview_url: { + type: 'string', + description: 'URL to 30-second preview', + condition: { field: 'operation', value: 'spotify_get_track' }, + }, + + // === ALBUM OUTPUTS === + album_type: { + type: 'string', + description: 'Album type (album, single, compilation)', + condition: { field: 'operation', value: 'spotify_get_album' }, + }, + release_date: { + type: 'string', + description: 'Release date', + condition: { field: 'operation', value: ['spotify_get_album', 'spotify_get_episode'] }, + }, + label: { + type: 'string', + description: 'Record label', + condition: { field: 'operation', value: 'spotify_get_album' }, + }, + total_tracks: { + type: 'number', + description: 'Total tracks', + condition: { field: 'operation', value: ['spotify_get_album', 'spotify_get_playlist'] }, + }, + genres: { + type: 'json', + description: 'List of genres', + condition: { field: 'operation', value: ['spotify_get_album', 'spotify_get_artist'] }, + }, + + // === ARTIST OUTPUTS === + followers: { + type: 'number', + description: 'Number of followers', + condition: { + field: 'operation', + value: ['spotify_get_artist', 'spotify_get_current_user', 'spotify_get_user_profile'], + }, + }, + + // === PLAYLIST OUTPUTS === + description: { + type: 'string', + description: 'Description', + condition: { + field: 'operation', + value: [ + 'spotify_get_playlist', + 'spotify_get_show', + 'spotify_get_episode', + 'spotify_get_audiobook', + 'spotify_create_playlist', + ], + }, + }, + owner: { + type: 'json', + description: 'Playlist owner information', + condition: { field: 'operation', value: ['spotify_get_playlist', 'spotify_create_playlist'] }, + }, + public: { + type: 'boolean', + description: 'Whether playlist is public', + condition: { field: 'operation', value: ['spotify_get_playlist', 'spotify_create_playlist'] }, + }, + collaborative: { + type: 'boolean', + description: 'Whether playlist is collaborative', + condition: { field: 'operation', value: ['spotify_get_playlist', 'spotify_create_playlist'] }, + }, + snapshot_id: { + type: 'string', + description: 'Playlist version snapshot ID', + condition: { + field: 'operation', + value: [ + 'spotify_get_playlist', + 'spotify_create_playlist', + 'spotify_add_tracks_to_playlist', + 'spotify_remove_tracks_from_playlist', + 'spotify_reorder_playlist_items', + 'spotify_replace_playlist_items', + ], + }, + }, + + // === SHOW/PODCAST OUTPUTS === + publisher: { + type: 'string', + description: 'Publisher name', + condition: { field: 'operation', value: ['spotify_get_show', 'spotify_get_audiobook'] }, + }, + total_episodes: { + type: 'number', + description: 'Total episodes in show', + condition: { field: 'operation', value: 'spotify_get_show' }, + }, + shows: { + type: 'json', + description: 'List of shows/podcasts', + condition: { field: 'operation', value: ['spotify_get_shows', 'spotify_get_saved_shows'] }, + }, + languages: { + type: 'json', + description: 'List of languages', + condition: { field: 'operation', value: ['spotify_get_show', 'spotify_get_audiobook'] }, + }, + + // === EPISODE OUTPUTS === + show: { + type: 'json', + description: 'Parent show information', + condition: { field: 'operation', value: 'spotify_get_episode' }, + }, + episodes: { + type: 'json', + description: 'List of episodes', + condition: { + field: 'operation', + value: ['spotify_get_episodes', 'spotify_get_show_episodes', 'spotify_get_saved_episodes'], + }, + }, + + // === AUDIOBOOK OUTPUTS === + authors: { + type: 'json', + description: 'List of authors', + condition: { field: 'operation', value: 'spotify_get_audiobook' }, + }, + narrators: { + type: 'json', + description: 'List of narrators', + condition: { field: 'operation', value: 'spotify_get_audiobook' }, + }, + total_chapters: { + type: 'number', + description: 'Total chapters', + condition: { field: 'operation', value: 'spotify_get_audiobook' }, + }, + audiobooks: { + type: 'json', + description: 'List of audiobooks', + condition: { + field: 'operation', + value: ['spotify_get_audiobooks', 'spotify_get_saved_audiobooks'], + }, + }, + chapters: { + type: 'json', + description: 'List of chapters', + condition: { field: 'operation', value: 'spotify_get_audiobook_chapters' }, + }, + + // === USER PROFILE OUTPUTS === + display_name: { + type: 'string', + description: 'User display name', + condition: { + field: 'operation', + value: ['spotify_get_current_user', 'spotify_get_user_profile'], + }, + }, + email: { + type: 'string', + description: 'User email address', + condition: { field: 'operation', value: 'spotify_get_current_user' }, + }, + country: { + type: 'string', + description: 'User country code', + condition: { field: 'operation', value: 'spotify_get_current_user' }, + }, + product: { + type: 'string', + description: 'Subscription level (free, premium)', + condition: { field: 'operation', value: 'spotify_get_current_user' }, + }, + + // === PLAYER STATE OUTPUTS === + is_playing: { + type: 'boolean', + description: 'Whether playback is active', + condition: { + field: 'operation', + value: ['spotify_get_playback_state', 'spotify_get_currently_playing'], + }, + }, + device: { + type: 'json', + description: 'Active device information', + condition: { field: 'operation', value: 'spotify_get_playback_state' }, + }, + devices: { + type: 'json', + description: 'Available playback devices', + condition: { field: 'operation', value: 'spotify_get_devices' }, + }, + progress_ms: { + type: 'number', + description: 'Current playback position in ms', + condition: { + field: 'operation', + value: ['spotify_get_playback_state', 'spotify_get_currently_playing'], + }, + }, + currently_playing_type: { + type: 'string', + description: 'Type of content (track, episode, ad)', + condition: { field: 'operation', value: 'spotify_get_playback_state' }, + }, + shuffle_state: { + type: 'boolean', + description: 'Whether shuffle is enabled', + condition: { field: 'operation', value: 'spotify_get_playback_state' }, + }, + repeat_state: { + type: 'string', + description: 'Repeat mode (off, track, context)', + condition: { field: 'operation', value: 'spotify_get_playback_state' }, + }, + track: { + type: 'json', + description: 'Currently playing track', + condition: { + field: 'operation', + value: ['spotify_get_playback_state', 'spotify_get_currently_playing'], + }, + }, + currently_playing: { + type: 'json', + description: 'Currently playing item', + condition: { field: 'operation', value: 'spotify_get_queue' }, + }, + queue: { + type: 'json', + description: 'Upcoming tracks in queue', + condition: { field: 'operation', value: 'spotify_get_queue' }, + }, + + // === RECENTLY PLAYED OUTPUTS === + items: { + type: 'json', + description: 'List of recently played items', + condition: { field: 'operation', value: 'spotify_get_recently_played' }, + }, + + // === BROWSE OUTPUTS === + categories: { + type: 'json', + description: 'List of browse categories', + condition: { field: 'operation', value: 'spotify_get_categories' }, + }, + markets: { + type: 'json', + description: 'List of available market codes', + condition: { field: 'operation', value: 'spotify_get_markets' }, + }, + + // === CHECK SAVED OUTPUTS === + results: { + type: 'json', + description: 'Check operation results (id and saved boolean)', + condition: { + field: 'operation', + value: [ + 'spotify_check_saved_tracks', + 'spotify_check_saved_albums', + 'spotify_check_saved_shows', + 'spotify_check_saved_episodes', + 'spotify_check_saved_audiobooks', + 'spotify_check_following', + 'spotify_check_playlist_followers', + ], + }, + }, + all_saved: { + type: 'boolean', + description: 'Whether all tracks are saved', + condition: { field: 'operation', value: 'spotify_check_saved_tracks' }, + }, + none_saved: { + type: 'boolean', + description: 'Whether no tracks are saved', + condition: { field: 'operation', value: 'spotify_check_saved_tracks' }, + }, + + // === PAGINATION OUTPUTS === + total: { + type: 'number', + description: 'Total number of items', + condition: { + field: 'operation', + value: [ + 'spotify_get_album_tracks', + 'spotify_get_artist_albums', + 'spotify_get_playlist_tracks', + 'spotify_get_user_playlists', + 'spotify_get_saved_tracks', + 'spotify_get_saved_albums', + 'spotify_get_top_tracks', + 'spotify_get_top_artists', + 'spotify_get_new_releases', + 'spotify_get_categories', + ], + }, + }, + next: { + type: 'string', + description: 'URL for next page of results', + condition: { + field: 'operation', + value: [ + 'spotify_get_album_tracks', + 'spotify_get_artist_albums', + 'spotify_get_playlist_tracks', + 'spotify_get_user_playlists', + 'spotify_get_saved_tracks', + 'spotify_get_saved_albums', + 'spotify_get_top_tracks', + 'spotify_get_top_artists', + 'spotify_get_recently_played', + 'spotify_get_new_releases', + ], + }, + }, + + // === OPERATION RESULT OUTPUTS === + success: { + type: 'boolean', + description: 'Whether operation succeeded', + condition: { + field: 'operation', + value: [ + 'spotify_play', + 'spotify_pause', + 'spotify_skip_next', + 'spotify_skip_previous', + 'spotify_seek', + 'spotify_set_volume', + 'spotify_set_repeat', + 'spotify_set_shuffle', + 'spotify_transfer_playback', + 'spotify_add_to_queue', + 'spotify_save_tracks', + 'spotify_remove_saved_tracks', + 'spotify_save_albums', + 'spotify_remove_saved_albums', + 'spotify_save_shows', + 'spotify_remove_saved_shows', + 'spotify_save_episodes', + 'spotify_remove_saved_episodes', + 'spotify_save_audiobooks', + 'spotify_remove_saved_audiobooks', + 'spotify_follow_artists', + 'spotify_unfollow_artists', + 'spotify_follow_playlist', + 'spotify_unfollow_playlist', + 'spotify_update_playlist', + 'spotify_add_playlist_cover', + ], + }, + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index ef3d36c0f2..ca1f30e845 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -101,6 +101,7 @@ import { SharepointBlock } from '@/blocks/blocks/sharepoint' import { ShopifyBlock } from '@/blocks/blocks/shopify' import { SlackBlock } from '@/blocks/blocks/slack' import { SmtpBlock } from '@/blocks/blocks/smtp' +import { SpotifyBlock } from '@/blocks/blocks/spotify' import { SSHBlock } from '@/blocks/blocks/ssh' import { StagehandBlock } from '@/blocks/blocks/stagehand' import { StartTriggerBlock } from '@/blocks/blocks/start_trigger' @@ -241,6 +242,7 @@ export const registry: Record = { sharepoint: SharepointBlock, shopify: ShopifyBlock, slack: SlackBlock, + spotify: SpotifyBlock, smtp: SmtpBlock, sftp: SftpBlock, ssh: SSHBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index e88000cabe..f9e690a726 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4203,3 +4203,15 @@ export function RssIcon(props: SVGProps) { ) } + +export function SpotifyIcon(props: SVGProps) { + return ( + + + + + ) +} diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 901a37e8b1..6123656f75 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -222,6 +222,7 @@ export const auth = betterAuth({ 'pipedrive', 'hubspot', 'linkedin', + 'spotify', // Common SSO provider patterns ...SSO_TRUSTED_PROVIDERS, @@ -1838,6 +1839,72 @@ export const auth = betterAuth({ }, }, + // Spotify provider + { + providerId: 'spotify', + clientId: env.SPOTIFY_CLIENT_ID as string, + clientSecret: env.SPOTIFY_CLIENT_SECRET as string, + authorizationUrl: 'https://accounts.spotify.com/authorize', + tokenUrl: 'https://accounts.spotify.com/api/token', + userInfoUrl: 'https://api.spotify.com/v1/me', + scopes: [ + 'user-read-private', + 'user-read-email', + 'user-library-read', + 'user-library-modify', + 'playlist-read-private', + 'playlist-read-collaborative', + 'playlist-modify-public', + 'playlist-modify-private', + 'user-read-playback-state', + 'user-modify-playback-state', + 'user-read-currently-playing', + 'user-read-recently-played', + 'user-top-read', + 'user-follow-read', + 'user-follow-modify', + 'user-read-playback-position', + 'ugc-image-upload', + ], + responseType: 'code', + authentication: 'basic', + redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/spotify`, + getUserInfo: async (tokens) => { + try { + logger.info('Fetching Spotify user profile') + + const response = await fetch('https://api.spotify.com/v1/me', { + headers: { + Authorization: `Bearer ${tokens.accessToken}`, + }, + }) + + if (!response.ok) { + logger.error('Failed to fetch Spotify user info', { + status: response.status, + statusText: response.statusText, + }) + throw new Error('Failed to fetch user info') + } + + const profile = await response.json() + + return { + id: profile.id, + name: profile.display_name || 'Spotify User', + email: profile.email || `${profile.id}@spotify.user`, + emailVerified: true, + image: profile.images?.[0]?.url || undefined, + createdAt: new Date(), + updatedAt: new Date(), + } + } catch (error) { + logger.error('Error in Spotify getUserInfo:', { error }) + return null + } + }, + }, + // WordPress.com provider { providerId: 'wordpress', diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index ac5ec6ffe0..069aeff3ea 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -230,6 +230,8 @@ export const env = createEnv({ ZOOM_CLIENT_SECRET: z.string().optional(), // Zoom OAuth client secret WORDPRESS_CLIENT_ID: z.string().optional(), // WordPress.com OAuth client ID WORDPRESS_CLIENT_SECRET: z.string().optional(), // WordPress.com OAuth client secret + SPOTIFY_CLIENT_ID: z.string().optional(), // Spotify OAuth client ID + SPOTIFY_CLIENT_SECRET: z.string().optional(), // Spotify OAuth client secret // E2B Remote Code Execution E2B_ENABLED: z.string().optional(), // Enable E2B remote code execution diff --git a/apps/sim/lib/logs/execution/logging-session.ts b/apps/sim/lib/logs/execution/logging-session.ts index 92b76ae364..f7c4f12778 100644 --- a/apps/sim/lib/logs/execution/logging-session.ts +++ b/apps/sim/lib/logs/execution/logging-session.ts @@ -175,9 +175,16 @@ export class LoggingSession { logger.debug(`[${this.requestId}] Completed logging for execution ${this.executionId}`) } } catch (error) { - if (this.requestId) { - logger.error(`[${this.requestId}] Failed to complete logging:`, error) - } + // Always log completion failures with full details - these should not be silent + logger.error(`Failed to complete logging for execution ${this.executionId}:`, { + requestId: this.requestId, + workflowId: this.workflowId, + executionId: this.executionId, + error: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined, + }) + // Rethrow so safeComplete can decide what to do + throw error } } @@ -247,12 +254,21 @@ export class LoggingSession { } if (this.requestId) { - logger.debug(`[${this.requestId}] Completed logging for execution ${this.executionId}`) + logger.debug( + `[${this.requestId}] Completed error logging for execution ${this.executionId}` + ) } } catch (enhancedError) { - if (this.requestId) { - logger.error(`[${this.requestId}] Failed to complete logging:`, enhancedError) - } + // Always log completion failures with full details + logger.error(`Failed to complete error logging for execution ${this.executionId}:`, { + requestId: this.requestId, + workflowId: this.workflowId, + executionId: this.executionId, + error: enhancedError instanceof Error ? enhancedError.message : String(enhancedError), + stack: enhancedError instanceof Error ? enhancedError.stack : undefined, + }) + // Rethrow so safeCompleteWithError can decide what to do + throw enhancedError } } @@ -315,9 +331,10 @@ export class LoggingSession { try { await this.complete(params) } catch (error) { - if (this.requestId) { - logger.error(`[${this.requestId}] Logging completion failed:`, error) - } + // Error already logged in complete(), log a summary here + logger.warn( + `[${this.requestId || 'unknown'}] Logging completion failed for execution ${this.executionId} - execution data not persisted` + ) } } @@ -325,9 +342,10 @@ export class LoggingSession { try { await this.completeWithError(error) } catch (enhancedError) { - if (this.requestId) { - logger.error(`[${this.requestId}] Logging error completion failed:`, enhancedError) - } + // Error already logged in completeWithError(), log a summary here + logger.warn( + `[${this.requestId || 'unknown'}] Error logging completion failed for execution ${this.executionId} - execution data not persisted` + ) } } } diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index 3e4181aadf..7b4f53caaf 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -31,6 +31,7 @@ import { SalesforceIcon, ShopifyIcon, SlackIcon, + SpotifyIcon, // SupabaseIcon, TrelloIcon, WealthboxIcon, @@ -70,6 +71,7 @@ export type OAuthProvider = | 'shopify' | 'zoom' | 'wordpress' + | 'spotify' | string export type OAuthService = @@ -111,6 +113,8 @@ export type OAuthService = | 'shopify' | 'zoom' | 'wordpress' + | 'spotify' + export interface OAuthProviderConfig { id: OAuthProvider name: string @@ -891,6 +895,41 @@ export const OAUTH_PROVIDERS: Record = { }, defaultService: 'wordpress', }, + spotify: { + id: 'spotify', + name: 'Spotify', + icon: (props) => SpotifyIcon(props), + services: { + spotify: { + id: 'spotify', + name: 'Spotify', + description: 'Search music, manage playlists, control playback, and access your library.', + providerId: 'spotify', + icon: (props) => SpotifyIcon(props), + baseProviderIcon: (props) => SpotifyIcon(props), + scopes: [ + 'user-read-private', + 'user-read-email', + 'user-library-read', + 'user-library-modify', + 'playlist-read-private', + 'playlist-read-collaborative', + 'playlist-modify-public', + 'playlist-modify-private', + 'user-read-playback-state', + 'user-modify-playback-state', + 'user-read-currently-playing', + 'user-read-recently-played', + 'user-top-read', + 'user-follow-read', + 'user-follow-modify', + 'user-read-playback-position', + 'ugc-image-upload', + ], + }, + }, + defaultService: 'spotify', + }, } /** @@ -1470,6 +1509,19 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig { supportsRefreshTokenRotation: false, } } + case 'spotify': { + const { clientId, clientSecret } = getCredentials( + env.SPOTIFY_CLIENT_ID, + env.SPOTIFY_CLIENT_SECRET + ) + return { + tokenEndpoint: 'https://accounts.spotify.com/api/token', + clientId, + clientSecret, + useBasicAuth: true, + supportsRefreshTokenRotation: false, + } + } default: throw new Error(`Unsupported provider: ${provider}`) } diff --git a/apps/sim/package.json b/apps/sim/package.json index c3e9d27950..83d469da3a 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -20,7 +20,7 @@ "test:coverage": "vitest run --coverage", "email:dev": "email dev --dir components/emails", "type-check": "tsc --noEmit", - "test:billing:suite": "bun run scripts/test-billing-suite.ts" + "generate-docs": "bun run ../../scripts/generate-docs.ts" }, "dependencies": { "@anthropic-ai/sdk": "^0.39.0", diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index d112476053..ed28b15e1b 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1014,6 +1014,86 @@ import { } from '@/tools/slack' import { smsSendTool } from '@/tools/sms' import { smtpSendMailTool } from '@/tools/smtp' +import { + spotifyAddPlaylistCoverTool, + spotifyAddToQueueTool, + spotifyAddTracksToPlaylistTool, + spotifyCheckFollowingTool, + spotifyCheckPlaylistFollowersTool, + spotifyCheckSavedAlbumsTool, + spotifyCheckSavedAudiobooksTool, + spotifyCheckSavedEpisodesTool, + spotifyCheckSavedShowsTool, + spotifyCheckSavedTracksTool, + spotifyCreatePlaylistTool, + spotifyFollowArtistsTool, + spotifyFollowPlaylistTool, + spotifyGetAlbumsTool, + spotifyGetAlbumTool, + spotifyGetAlbumTracksTool, + spotifyGetArtistAlbumsTool, + spotifyGetArtistsTool, + spotifyGetArtistTool, + spotifyGetArtistTopTracksTool, + spotifyGetAudiobookChaptersTool, + spotifyGetAudiobooksTool, + spotifyGetAudiobookTool, + spotifyGetCategoriesTool, + spotifyGetCurrentlyPlayingTool, + spotifyGetCurrentUserTool, + spotifyGetDevicesTool, + spotifyGetEpisodesTool, + spotifyGetEpisodeTool, + spotifyGetFollowedArtistsTool, + spotifyGetMarketsTool, + spotifyGetNewReleasesTool, + spotifyGetPlaybackStateTool, + spotifyGetPlaylistCoverTool, + spotifyGetPlaylistTool, + spotifyGetPlaylistTracksTool, + spotifyGetQueueTool, + spotifyGetRecentlyPlayedTool, + spotifyGetSavedAlbumsTool, + spotifyGetSavedAudiobooksTool, + spotifyGetSavedEpisodesTool, + spotifyGetSavedShowsTool, + spotifyGetSavedTracksTool, + spotifyGetShowEpisodesTool, + spotifyGetShowsTool, + spotifyGetShowTool, + spotifyGetTopArtistsTool, + spotifyGetTopTracksTool, + spotifyGetTracksTool, + spotifyGetTrackTool, + spotifyGetUserPlaylistsTool, + spotifyGetUserProfileTool, + spotifyPauseTool, + spotifyPlayTool, + spotifyRemoveSavedAlbumsTool, + spotifyRemoveSavedAudiobooksTool, + spotifyRemoveSavedEpisodesTool, + spotifyRemoveSavedShowsTool, + spotifyRemoveSavedTracksTool, + spotifyRemoveTracksFromPlaylistTool, + spotifyReorderPlaylistItemsTool, + spotifyReplacePlaylistItemsTool, + spotifySaveAlbumsTool, + spotifySaveAudiobooksTool, + spotifySaveEpisodesTool, + spotifySaveShowsTool, + spotifySaveTracksTool, + spotifySearchTool, + spotifySeekTool, + spotifySetRepeatTool, + spotifySetShuffleTool, + spotifySetVolumeTool, + spotifySkipNextTool, + spotifySkipPreviousTool, + spotifyTransferPlaybackTool, + spotifyUnfollowArtistsTool, + spotifyUnfollowPlaylistTool, + spotifyUpdatePlaylistTool, +} from '@/tools/spotify' import { sshCheckCommandExistsTool, sshCheckFileExistsTool, @@ -2429,4 +2509,83 @@ export const tools: Record = { zoom_get_meeting_recordings: zoomGetMeetingRecordingsTool, zoom_delete_recording: zoomDeleteRecordingTool, zoom_list_past_participants: zoomListPastParticipantsTool, + // Spotify + spotify_search: spotifySearchTool, + spotify_get_track: spotifyGetTrackTool, + spotify_get_tracks: spotifyGetTracksTool, + spotify_get_album: spotifyGetAlbumTool, + spotify_get_albums: spotifyGetAlbumsTool, + spotify_get_album_tracks: spotifyGetAlbumTracksTool, + spotify_get_saved_albums: spotifyGetSavedAlbumsTool, + spotify_save_albums: spotifySaveAlbumsTool, + spotify_remove_saved_albums: spotifyRemoveSavedAlbumsTool, + spotify_check_saved_albums: spotifyCheckSavedAlbumsTool, + spotify_get_artist: spotifyGetArtistTool, + spotify_get_artists: spotifyGetArtistsTool, + spotify_get_artist_albums: spotifyGetArtistAlbumsTool, + spotify_get_artist_top_tracks: spotifyGetArtistTopTracksTool, + spotify_follow_artists: spotifyFollowArtistsTool, + spotify_unfollow_artists: spotifyUnfollowArtistsTool, + spotify_get_followed_artists: spotifyGetFollowedArtistsTool, + spotify_check_following: spotifyCheckFollowingTool, + spotify_get_show: spotifyGetShowTool, + spotify_get_shows: spotifyGetShowsTool, + spotify_get_show_episodes: spotifyGetShowEpisodesTool, + spotify_get_saved_shows: spotifyGetSavedShowsTool, + spotify_save_shows: spotifySaveShowsTool, + spotify_remove_saved_shows: spotifyRemoveSavedShowsTool, + spotify_check_saved_shows: spotifyCheckSavedShowsTool, + spotify_get_episode: spotifyGetEpisodeTool, + spotify_get_episodes: spotifyGetEpisodesTool, + spotify_get_saved_episodes: spotifyGetSavedEpisodesTool, + spotify_save_episodes: spotifySaveEpisodesTool, + spotify_remove_saved_episodes: spotifyRemoveSavedEpisodesTool, + spotify_check_saved_episodes: spotifyCheckSavedEpisodesTool, + spotify_get_audiobook: spotifyGetAudiobookTool, + spotify_get_audiobooks: spotifyGetAudiobooksTool, + spotify_get_audiobook_chapters: spotifyGetAudiobookChaptersTool, + spotify_get_saved_audiobooks: spotifyGetSavedAudiobooksTool, + spotify_save_audiobooks: spotifySaveAudiobooksTool, + spotify_remove_saved_audiobooks: spotifyRemoveSavedAudiobooksTool, + spotify_check_saved_audiobooks: spotifyCheckSavedAudiobooksTool, + spotify_get_playlist: spotifyGetPlaylistTool, + spotify_get_playlist_tracks: spotifyGetPlaylistTracksTool, + spotify_get_playlist_cover: spotifyGetPlaylistCoverTool, + spotify_get_user_playlists: spotifyGetUserPlaylistsTool, + spotify_create_playlist: spotifyCreatePlaylistTool, + spotify_update_playlist: spotifyUpdatePlaylistTool, + spotify_add_playlist_cover: spotifyAddPlaylistCoverTool, + spotify_add_tracks_to_playlist: spotifyAddTracksToPlaylistTool, + spotify_remove_tracks_from_playlist: spotifyRemoveTracksFromPlaylistTool, + spotify_reorder_playlist_items: spotifyReorderPlaylistItemsTool, + spotify_replace_playlist_items: spotifyReplacePlaylistItemsTool, + spotify_follow_playlist: spotifyFollowPlaylistTool, + spotify_unfollow_playlist: spotifyUnfollowPlaylistTool, + spotify_check_playlist_followers: spotifyCheckPlaylistFollowersTool, + spotify_get_current_user: spotifyGetCurrentUserTool, + spotify_get_user_profile: spotifyGetUserProfileTool, + spotify_get_top_tracks: spotifyGetTopTracksTool, + spotify_get_top_artists: spotifyGetTopArtistsTool, + spotify_get_saved_tracks: spotifyGetSavedTracksTool, + spotify_save_tracks: spotifySaveTracksTool, + spotify_remove_saved_tracks: spotifyRemoveSavedTracksTool, + spotify_check_saved_tracks: spotifyCheckSavedTracksTool, + spotify_get_recently_played: spotifyGetRecentlyPlayedTool, + spotify_get_new_releases: spotifyGetNewReleasesTool, + spotify_get_categories: spotifyGetCategoriesTool, + spotify_get_markets: spotifyGetMarketsTool, + spotify_get_playback_state: spotifyGetPlaybackStateTool, + spotify_get_currently_playing: spotifyGetCurrentlyPlayingTool, + spotify_get_devices: spotifyGetDevicesTool, + spotify_get_queue: spotifyGetQueueTool, + spotify_play: spotifyPlayTool, + spotify_pause: spotifyPauseTool, + spotify_skip_next: spotifySkipNextTool, + spotify_skip_previous: spotifySkipPreviousTool, + spotify_seek: spotifySeekTool, + spotify_add_to_queue: spotifyAddToQueueTool, + spotify_set_volume: spotifySetVolumeTool, + spotify_set_repeat: spotifySetRepeatTool, + spotify_set_shuffle: spotifySetShuffleTool, + spotify_transfer_playback: spotifyTransferPlaybackTool, } diff --git a/apps/sim/tools/spotify/add_playlist_cover.ts b/apps/sim/tools/spotify/add_playlist_cover.ts new file mode 100644 index 0000000000..551958378e --- /dev/null +++ b/apps/sim/tools/spotify/add_playlist_cover.ts @@ -0,0 +1,58 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyAddPlaylistCoverParams { + accessToken: string + playlistId: string + imageBase64: string +} + +interface SpotifyAddPlaylistCoverResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyAddPlaylistCoverTool: ToolConfig< + SpotifyAddPlaylistCoverParams, + SpotifyAddPlaylistCoverResponse +> = { + id: 'spotify_add_playlist_cover', + name: 'Spotify Add Playlist Cover', + description: 'Upload a custom cover image for a playlist. Image must be JPEG and under 256KB.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private', 'ugc-image-upload'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + imageBase64: { + type: 'string', + required: true, + description: 'Base64-encoded JPEG image (max 256KB)', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/images`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'image/jpeg', + }), + body: (params) => params.imageBase64, + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether upload succeeded' }, + }, +} diff --git a/apps/sim/tools/spotify/add_to_queue.ts b/apps/sim/tools/spotify/add_to_queue.ts new file mode 100644 index 0000000000..7753fe1231 --- /dev/null +++ b/apps/sim/tools/spotify/add_to_queue.ts @@ -0,0 +1,59 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyAddToQueueParams, SpotifyAddToQueueResponse } from './types' + +export const spotifyAddToQueueTool: ToolConfig = + { + id: 'spotify_add_to_queue', + name: 'Spotify Add to Queue', + description: "Add a track to the user's playback queue.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + uri: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Spotify URI of the track to add (e.g., "spotify:track:xxx")', + }, + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID. If not provided, uses active device.', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/me/player/queue?uri=${encodeURIComponent(params.uri)}` + if (params.device_id) { + url += `&device_id=${params.device_id}` + } + return url + }, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether track was added to queue' }, + }, + } diff --git a/apps/sim/tools/spotify/add_tracks_to_playlist.ts b/apps/sim/tools/spotify/add_tracks_to_playlist.ts new file mode 100644 index 0000000000..0fbd2a610f --- /dev/null +++ b/apps/sim/tools/spotify/add_tracks_to_playlist.ts @@ -0,0 +1,71 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyAddTracksToPlaylistParams, SpotifyAddTracksToPlaylistResponse } from './types' + +export const spotifyAddTracksToPlaylistTool: ToolConfig< + SpotifyAddTracksToPlaylistParams, + SpotifyAddTracksToPlaylistResponse +> = { + id: 'spotify_add_tracks_to_playlist', + name: 'Spotify Add Tracks to Playlist', + description: 'Add one or more tracks to a Spotify playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the playlist', + }, + uris: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated Spotify URIs (e.g., "spotify:track:xxx,spotify:track:yyy")', + }, + position: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Position to insert tracks (0-based). If omitted, tracks are appended.', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/tracks`, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const uris = params.uris.split(',').map((uri) => uri.trim()) + const body: any = { uris } + if (params.position !== undefined) { + body.position = params.position + } + return body + }, + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + return { + success: true, + output: { + snapshot_id: data.snapshot_id, + }, + } + }, + + outputs: { + snapshot_id: { type: 'string', description: 'New playlist snapshot ID after modification' }, + }, +} diff --git a/apps/sim/tools/spotify/check_following.ts b/apps/sim/tools/spotify/check_following.ts new file mode 100644 index 0000000000..c1bcca245c --- /dev/null +++ b/apps/sim/tools/spotify/check_following.ts @@ -0,0 +1,64 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckFollowingParams { + accessToken: string + type: string + ids: string +} + +interface SpotifyCheckFollowingResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckFollowingTool: ToolConfig< + SpotifyCheckFollowingParams, + SpotifyCheckFollowingResponse +> = { + id: 'spotify_check_following', + name: 'Spotify Check Following', + description: 'Check if the user follows artists or users.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-follow-read'], + }, + + params: { + type: { + type: 'string', + required: true, + description: 'Type to check: "artist" or "user"', + }, + ids: { + type: 'string', + required: true, + description: 'Comma-separated artist or user IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.ids + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/following/contains?type=${params.type}&ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each ID' }, + }, +} diff --git a/apps/sim/tools/spotify/check_playlist_followers.ts b/apps/sim/tools/spotify/check_playlist_followers.ts new file mode 100644 index 0000000000..973647563b --- /dev/null +++ b/apps/sim/tools/spotify/check_playlist_followers.ts @@ -0,0 +1,64 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckPlaylistFollowersParams { + accessToken: string + playlistId: string + userIds: string +} + +interface SpotifyCheckPlaylistFollowersResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckPlaylistFollowersTool: ToolConfig< + SpotifyCheckPlaylistFollowersParams, + SpotifyCheckPlaylistFollowersResponse +> = { + id: 'spotify_check_playlist_followers', + name: 'Spotify Check Playlist Followers', + description: 'Check if users follow a playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-read-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + userIds: { + type: 'string', + required: true, + description: 'Comma-separated user IDs to check (max 5)', + }, + }, + + request: { + url: (params) => { + const ids = params.userIds + .split(',') + .map((id) => id.trim()) + .slice(0, 5) + .join(',') + return `https://api.spotify.com/v1/playlists/${params.playlistId}/followers/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each user' }, + }, +} diff --git a/apps/sim/tools/spotify/check_saved_albums.ts b/apps/sim/tools/spotify/check_saved_albums.ts new file mode 100644 index 0000000000..751d6260c1 --- /dev/null +++ b/apps/sim/tools/spotify/check_saved_albums.ts @@ -0,0 +1,58 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckSavedAlbumsParams { + accessToken: string + albumIds: string +} + +interface SpotifyCheckSavedAlbumsResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckSavedAlbumsTool: ToolConfig< + SpotifyCheckSavedAlbumsParams, + SpotifyCheckSavedAlbumsResponse +> = { + id: 'spotify_check_saved_albums', + name: 'Spotify Check Saved Albums', + description: 'Check if albums are saved in library.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + albumIds: { + type: 'string', + required: true, + description: 'Comma-separated album IDs (max 20)', + }, + }, + + request: { + url: (params) => { + const ids = params.albumIds + .split(',') + .map((id) => id.trim()) + .slice(0, 20) + .join(',') + return `https://api.spotify.com/v1/me/albums/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each album' }, + }, +} diff --git a/apps/sim/tools/spotify/check_saved_audiobooks.ts b/apps/sim/tools/spotify/check_saved_audiobooks.ts new file mode 100644 index 0000000000..2c14ebe01a --- /dev/null +++ b/apps/sim/tools/spotify/check_saved_audiobooks.ts @@ -0,0 +1,58 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckSavedAudiobooksParams { + accessToken: string + audiobookIds: string +} + +interface SpotifyCheckSavedAudiobooksResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckSavedAudiobooksTool: ToolConfig< + SpotifyCheckSavedAudiobooksParams, + SpotifyCheckSavedAudiobooksResponse +> = { + id: 'spotify_check_saved_audiobooks', + name: 'Spotify Check Saved Audiobooks', + description: 'Check if audiobooks are saved in library.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + audiobookIds: { + type: 'string', + required: true, + description: 'Comma-separated audiobook IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.audiobookIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/audiobooks/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each audiobook' }, + }, +} diff --git a/apps/sim/tools/spotify/check_saved_episodes.ts b/apps/sim/tools/spotify/check_saved_episodes.ts new file mode 100644 index 0000000000..45027e1dd3 --- /dev/null +++ b/apps/sim/tools/spotify/check_saved_episodes.ts @@ -0,0 +1,58 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckSavedEpisodesParams { + accessToken: string + episodeIds: string +} + +interface SpotifyCheckSavedEpisodesResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckSavedEpisodesTool: ToolConfig< + SpotifyCheckSavedEpisodesParams, + SpotifyCheckSavedEpisodesResponse +> = { + id: 'spotify_check_saved_episodes', + name: 'Spotify Check Saved Episodes', + description: 'Check if episodes are saved in library.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + episodeIds: { + type: 'string', + required: true, + description: 'Comma-separated episode IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.episodeIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/episodes/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each episode' }, + }, +} diff --git a/apps/sim/tools/spotify/check_saved_shows.ts b/apps/sim/tools/spotify/check_saved_shows.ts new file mode 100644 index 0000000000..22efd1e2fe --- /dev/null +++ b/apps/sim/tools/spotify/check_saved_shows.ts @@ -0,0 +1,58 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyCheckSavedShowsParams { + accessToken: string + showIds: string +} + +interface SpotifyCheckSavedShowsResponse extends ToolResponse { + output: { results: boolean[] } +} + +export const spotifyCheckSavedShowsTool: ToolConfig< + SpotifyCheckSavedShowsParams, + SpotifyCheckSavedShowsResponse +> = { + id: 'spotify_check_saved_shows', + name: 'Spotify Check Saved Shows', + description: 'Check if shows are saved in library.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + showIds: { + type: 'string', + required: true, + description: 'Comma-separated show IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.showIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/shows/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const results = await response.json() + return { success: true, output: { results } } + }, + + outputs: { + results: { type: 'json', description: 'Array of booleans for each show' }, + }, +} diff --git a/apps/sim/tools/spotify/check_saved_tracks.ts b/apps/sim/tools/spotify/check_saved_tracks.ts new file mode 100644 index 0000000000..0793d6e72a --- /dev/null +++ b/apps/sim/tools/spotify/check_saved_tracks.ts @@ -0,0 +1,71 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyCheckSavedTracksParams, SpotifyCheckSavedTracksResponse } from './types' + +export const spotifyCheckSavedTracksTool: ToolConfig< + SpotifyCheckSavedTracksParams, + SpotifyCheckSavedTracksResponse +> = { + id: 'spotify_check_saved_tracks', + name: 'Spotify Check Saved Tracks', + description: "Check if one or more tracks are saved in the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + trackIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated track IDs to check (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.trackIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/tracks/contains?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response, params): Promise => { + const data = await response.json() + const ids = (params?.trackIds || '') + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + + const results = ids.map((id, index) => ({ + id, + saved: data[index] || false, + })) + + return { + success: true, + output: { + results, + all_saved: data.every((saved: boolean) => saved), + none_saved: data.every((saved: boolean) => !saved), + }, + } + }, + + outputs: { + results: { type: 'json', description: 'Array of track IDs with saved status' }, + all_saved: { type: 'boolean', description: 'Whether all tracks are saved' }, + none_saved: { type: 'boolean', description: 'Whether no tracks are saved' }, + }, +} diff --git a/apps/sim/tools/spotify/create_playlist.ts b/apps/sim/tools/spotify/create_playlist.ts new file mode 100644 index 0000000000..c28cc0d2ee --- /dev/null +++ b/apps/sim/tools/spotify/create_playlist.ts @@ -0,0 +1,89 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyCreatePlaylistParams, SpotifyCreatePlaylistResponse } from './types' + +export const spotifyCreatePlaylistTool: ToolConfig< + SpotifyCreatePlaylistParams, + SpotifyCreatePlaylistResponse +> = { + id: 'spotify_create_playlist', + name: 'Spotify Create Playlist', + description: 'Create a new playlist for the current user on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the new playlist', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description for the playlist', + }, + public: { + type: 'boolean', + required: false, + visibility: 'user-only', + default: true, + description: 'Whether the playlist should be public', + }, + collaborative: { + type: 'boolean', + required: false, + visibility: 'user-only', + default: false, + description: 'Whether the playlist should be collaborative (requires public to be false)', + }, + }, + + request: { + url: () => 'https://api.spotify.com/v1/me/playlists', + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + name: params.name, + description: params.description || '', + public: params.public !== false, + collaborative: params.collaborative === true, + }), + }, + + transformResponse: async (response): Promise => { + const playlist = await response.json() + + return { + success: true, + output: { + id: playlist.id, + name: playlist.name, + description: playlist.description, + public: playlist.public, + collaborative: playlist.collaborative, + snapshot_id: playlist.snapshot_id, + external_url: playlist.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify playlist ID' }, + name: { type: 'string', description: 'Playlist name' }, + description: { type: 'string', description: 'Playlist description', optional: true }, + public: { type: 'boolean', description: 'Whether the playlist is public' }, + collaborative: { type: 'boolean', description: 'Whether collaborative' }, + snapshot_id: { type: 'string', description: 'Playlist snapshot ID' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/follow_artists.ts b/apps/sim/tools/spotify/follow_artists.ts new file mode 100644 index 0000000000..c1f91bf1cd --- /dev/null +++ b/apps/sim/tools/spotify/follow_artists.ts @@ -0,0 +1,64 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyFollowArtistsParams { + accessToken: string + artistIds: string +} + +interface SpotifyFollowArtistsResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifyFollowArtistsTool: ToolConfig< + SpotifyFollowArtistsParams, + SpotifyFollowArtistsResponse +> = { + id: 'spotify_follow_artists', + name: 'Spotify Follow Artists', + description: 'Follow one or more artists.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-follow-modify'], + }, + + params: { + artistIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated artist IDs to follow (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.artistIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/following?type=artist&ids=${ids}` + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether artists were followed successfully' }, + }, +} diff --git a/apps/sim/tools/spotify/follow_playlist.ts b/apps/sim/tools/spotify/follow_playlist.ts new file mode 100644 index 0000000000..62f2c6ea4d --- /dev/null +++ b/apps/sim/tools/spotify/follow_playlist.ts @@ -0,0 +1,61 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyFollowPlaylistParams { + accessToken: string + playlistId: string + public?: boolean +} + +interface SpotifyFollowPlaylistResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyFollowPlaylistTool: ToolConfig< + SpotifyFollowPlaylistParams, + SpotifyFollowPlaylistResponse +> = { + id: 'spotify_follow_playlist', + name: 'Spotify Follow Playlist', + description: 'Follow (save) a playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + public: { + type: 'boolean', + required: false, + default: true, + description: 'Whether the playlist will be in public playlists', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/followers`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + public: params.public ?? true, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether follow succeeded' }, + }, +} diff --git a/apps/sim/tools/spotify/get_album.ts b/apps/sim/tools/spotify/get_album.ts new file mode 100644 index 0000000000..7c85d3ce1e --- /dev/null +++ b/apps/sim/tools/spotify/get_album.ts @@ -0,0 +1,87 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetAlbumParams, SpotifyGetAlbumResponse } from './types' + +export const spotifyGetAlbumTool: ToolConfig = { + id: 'spotify_get_album', + name: 'Spotify Get Album', + description: + 'Get detailed information about an album on Spotify by its ID, including track listing.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + albumId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the album', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code for track availability', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/albums/${params.albumId}` + if (params.market) { + url += `?market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const album = await response.json() + + return { + success: true, + output: { + id: album.id, + name: album.name, + artists: album.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album_type: album.album_type, + total_tracks: album.total_tracks, + release_date: album.release_date, + label: album.label || '', + popularity: album.popularity, + genres: album.genres || [], + image_url: album.images?.[0]?.url || null, + tracks: (album.tracks?.items || []).map((t: any) => ({ + id: t.id, + name: t.name, + duration_ms: t.duration_ms, + track_number: t.track_number, + })), + external_url: album.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify album ID' }, + name: { type: 'string', description: 'Album name' }, + artists: { type: 'array', description: 'List of artists' }, + album_type: { type: 'string', description: 'Type of album (album, single, compilation)' }, + total_tracks: { type: 'number', description: 'Total number of tracks' }, + release_date: { type: 'string', description: 'Release date' }, + label: { type: 'string', description: 'Record label' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + genres: { type: 'array', description: 'List of genres' }, + image_url: { type: 'string', description: 'Album cover image URL', optional: true }, + tracks: { type: 'array', description: 'List of tracks on the album' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_album_tracks.ts b/apps/sim/tools/spotify/get_album_tracks.ts new file mode 100644 index 0000000000..c648307988 --- /dev/null +++ b/apps/sim/tools/spotify/get_album_tracks.ts @@ -0,0 +1,112 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetAlbumTracksParams { + accessToken: string + albumId: string + limit?: number + offset?: number + market?: string +} + +interface SpotifyGetAlbumTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + duration_ms: number + track_number: number + disc_number: number + explicit: boolean + preview_url: string | null + }> + total: number + next: string | null + } +} + +export const spotifyGetAlbumTracksTool: ToolConfig< + SpotifyGetAlbumTracksParams, + SpotifyGetAlbumTracksResponse +> = { + id: 'spotify_get_album_tracks', + name: 'Spotify Get Album Tracks', + description: 'Get the tracks from an album.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + albumId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify album ID', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of tracks to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of first track to return', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/albums/${params.albumId}/tracks?limit=${limit}&offset=${offset}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.items || []).map((track: any) => ({ + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + duration_ms: track.duration_ms, + track_number: track.track_number, + disc_number: track.disc_number, + explicit: track.explicit || false, + preview_url: track.preview_url || null, + })) + + return { + success: true, + output: { + tracks, + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + tracks: { type: 'json', description: 'List of tracks' }, + total: { type: 'number', description: 'Total number of tracks' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_albums.ts b/apps/sim/tools/spotify/get_albums.ts new file mode 100644 index 0000000000..2d6bcabc84 --- /dev/null +++ b/apps/sim/tools/spotify/get_albums.ts @@ -0,0 +1,94 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetAlbumsParams { + accessToken: string + albumIds: string + market?: string +} + +interface SpotifyGetAlbumsResponse extends ToolResponse { + output: { + albums: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + album_type: string + total_tracks: number + release_date: string + image_url: string | null + external_url: string + }> + } +} + +export const spotifyGetAlbumsTool: ToolConfig = { + id: 'spotify_get_albums', + name: 'Spotify Get Multiple Albums', + description: 'Get details for multiple albums by their IDs.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + albumIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated album IDs (max 20)', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const ids = params.albumIds + .split(',') + .map((id) => id.trim()) + .slice(0, 20) + .join(',') + let url = `https://api.spotify.com/v1/albums?ids=${ids}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const albums = (data.albums || []).map((album: any) => ({ + id: album.id, + name: album.name, + artists: album.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album_type: album.album_type, + total_tracks: album.total_tracks, + release_date: album.release_date, + image_url: album.images?.[0]?.url || null, + external_url: album.external_urls?.spotify || '', + })) + + return { + success: true, + output: { albums }, + } + }, + + outputs: { + albums: { type: 'json', description: 'List of albums' }, + }, +} diff --git a/apps/sim/tools/spotify/get_artist.ts b/apps/sim/tools/spotify/get_artist.ts new file mode 100644 index 0000000000..d8f223c7eb --- /dev/null +++ b/apps/sim/tools/spotify/get_artist.ts @@ -0,0 +1,59 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetArtistParams, SpotifyGetArtistResponse } from './types' + +export const spotifyGetArtistTool: ToolConfig = { + id: 'spotify_get_artist', + name: 'Spotify Get Artist', + description: 'Get detailed information about an artist on Spotify by their ID.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + artistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the artist', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/artists/${params.artistId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const artist = await response.json() + + return { + success: true, + output: { + id: artist.id, + name: artist.name, + genres: artist.genres || [], + popularity: artist.popularity, + followers: artist.followers?.total || 0, + image_url: artist.images?.[0]?.url || null, + external_url: artist.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify artist ID' }, + name: { type: 'string', description: 'Artist name' }, + genres: { type: 'array', description: 'List of genres associated with the artist' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + followers: { type: 'number', description: 'Number of followers' }, + image_url: { type: 'string', description: 'Artist image URL', optional: true }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_artist_albums.ts b/apps/sim/tools/spotify/get_artist_albums.ts new file mode 100644 index 0000000000..3498bfb957 --- /dev/null +++ b/apps/sim/tools/spotify/get_artist_albums.ts @@ -0,0 +1,116 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetArtistAlbumsParams, SpotifyGetArtistAlbumsResponse } from './types' + +export const spotifyGetArtistAlbumsTool: ToolConfig< + SpotifyGetArtistAlbumsParams, + SpotifyGetArtistAlbumsResponse +> = { + id: 'spotify_get_artist_albums', + name: 'Spotify Get Artist Albums', + description: 'Get albums by an artist on Spotify. Can filter by album type.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + artistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the artist', + }, + include_groups: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by album type: album, single, appears_on, compilation (comma-separated)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Maximum number of albums to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first album to return', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/artists/${params.artistId}/albums?limit=${limit}&offset=${offset}` + if (params.include_groups) { + url += `&include_groups=${encodeURIComponent(params.include_groups)}` + } + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const albums = (data.items || []).map((album: any) => ({ + id: album.id, + name: album.name, + album_type: album.album_type, + total_tracks: album.total_tracks, + release_date: album.release_date, + image_url: album.images?.[0]?.url || null, + external_url: album.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + albums, + total: data.total || albums.length, + next: data.next || null, + }, + } + }, + + outputs: { + albums: { + type: 'array', + description: "Artist's albums", + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify album ID' }, + name: { type: 'string', description: 'Album name' }, + album_type: { type: 'string', description: 'Type (album, single, compilation)' }, + total_tracks: { type: 'number', description: 'Number of tracks' }, + release_date: { type: 'string', description: 'Release date' }, + image_url: { type: 'string', description: 'Album cover URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of albums available' }, + next: { type: 'string', description: 'URL for next page of results', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_artist_top_tracks.ts b/apps/sim/tools/spotify/get_artist_top_tracks.ts new file mode 100644 index 0000000000..3b65203e43 --- /dev/null +++ b/apps/sim/tools/spotify/get_artist_top_tracks.ts @@ -0,0 +1,89 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetArtistTopTracksParams, SpotifyGetArtistTopTracksResponse } from './types' + +export const spotifyGetArtistTopTracksTool: ToolConfig< + SpotifyGetArtistTopTracksParams, + SpotifyGetArtistTopTracksResponse +> = { + id: 'spotify_get_artist_top_tracks', + name: 'Spotify Get Artist Top Tracks', + description: 'Get the top 10 most popular tracks by an artist on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + artistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the artist', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + default: 'US', + description: 'ISO 3166-1 alpha-2 country code (required for this endpoint)', + }, + }, + + request: { + url: (params) => { + const market = params.market || 'US' + return `https://api.spotify.com/v1/artists/${params.artistId}/top-tracks?market=${market}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.tracks || []).map((track: any) => ({ + id: track.id, + name: track.name, + album: { + id: track.album?.id || '', + name: track.album?.name || '', + image_url: track.album?.images?.[0]?.url || null, + }, + duration_ms: track.duration_ms, + popularity: track.popularity, + preview_url: track.preview_url, + external_url: track.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + tracks, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: "Artist's top tracks", + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify track ID' }, + name: { type: 'string', description: 'Track name' }, + album: { type: 'object', description: 'Album information' }, + duration_ms: { type: 'number', description: 'Track duration in milliseconds' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + preview_url: { type: 'string', description: 'URL to 30-second preview' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/spotify/get_artists.ts b/apps/sim/tools/spotify/get_artists.ts new file mode 100644 index 0000000000..62e69e35d4 --- /dev/null +++ b/apps/sim/tools/spotify/get_artists.ts @@ -0,0 +1,82 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetArtistsParams { + accessToken: string + artistIds: string +} + +interface SpotifyGetArtistsResponse extends ToolResponse { + output: { + artists: Array<{ + id: string + name: string + genres: string[] + popularity: number + followers: number + image_url: string | null + external_url: string + }> + } +} + +export const spotifyGetArtistsTool: ToolConfig = + { + id: 'spotify_get_artists', + name: 'Spotify Get Multiple Artists', + description: 'Get details for multiple artists by their IDs.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + artistIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated artist IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.artistIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/artists?ids=${ids}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const artists = (data.artists || []).map((artist: any) => ({ + id: artist.id, + name: artist.name, + genres: artist.genres || [], + popularity: artist.popularity || 0, + followers: artist.followers?.total || 0, + image_url: artist.images?.[0]?.url || null, + external_url: artist.external_urls?.spotify || '', + })) + + return { + success: true, + output: { artists }, + } + }, + + outputs: { + artists: { type: 'json', description: 'List of artists' }, + }, + } diff --git a/apps/sim/tools/spotify/get_audiobook.ts b/apps/sim/tools/spotify/get_audiobook.ts new file mode 100644 index 0000000000..5268432088 --- /dev/null +++ b/apps/sim/tools/spotify/get_audiobook.ts @@ -0,0 +1,95 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetAudiobookParams { + accessToken: string + audiobookId: string + market?: string +} + +interface SpotifyGetAudiobookResponse extends ToolResponse { + output: { + id: string + name: string + authors: Array<{ name: string }> + narrators: Array<{ name: string }> + publisher: string + description: string + total_chapters: number + languages: string[] + image_url: string | null + external_url: string + } +} + +export const spotifyGetAudiobookTool: ToolConfig< + SpotifyGetAudiobookParams, + SpotifyGetAudiobookResponse +> = { + id: 'spotify_get_audiobook', + name: 'Spotify Get Audiobook', + description: 'Get details for an audiobook.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + audiobookId: { + type: 'string', + required: true, + description: 'The Spotify audiobook ID', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/audiobooks/${params.audiobookId}` + if (params.market) url += `?market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const book = await response.json() + return { + success: true, + output: { + id: book.id, + name: book.name, + authors: book.authors || [], + narrators: book.narrators || [], + publisher: book.publisher || '', + description: book.description || '', + total_chapters: book.total_chapters || 0, + languages: book.languages || [], + image_url: book.images?.[0]?.url || null, + external_url: book.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Audiobook ID' }, + name: { type: 'string', description: 'Audiobook name' }, + authors: { type: 'json', description: 'Authors' }, + narrators: { type: 'json', description: 'Narrators' }, + publisher: { type: 'string', description: 'Publisher' }, + description: { type: 'string', description: 'Description' }, + total_chapters: { type: 'number', description: 'Total chapters' }, + languages: { type: 'json', description: 'Languages' }, + image_url: { type: 'string', description: 'Cover image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_audiobook_chapters.ts b/apps/sim/tools/spotify/get_audiobook_chapters.ts new file mode 100644 index 0000000000..451a082ce1 --- /dev/null +++ b/apps/sim/tools/spotify/get_audiobook_chapters.ts @@ -0,0 +1,104 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetAudiobookChaptersParams { + accessToken: string + audiobookId: string + limit?: number + offset?: number + market?: string +} + +interface SpotifyGetAudiobookChaptersResponse extends ToolResponse { + output: { + chapters: Array<{ + id: string + name: string + chapter_number: number + duration_ms: number + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +export const spotifyGetAudiobookChaptersTool: ToolConfig< + SpotifyGetAudiobookChaptersParams, + SpotifyGetAudiobookChaptersResponse +> = { + id: 'spotify_get_audiobook_chapters', + name: 'Spotify Get Audiobook Chapters', + description: 'Get chapters from an audiobook.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + audiobookId: { + type: 'string', + required: true, + description: 'The Spotify audiobook ID', + }, + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of chapters to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first chapter to return', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/audiobooks/${params.audiobookId}/chapters?limit=${limit}&offset=${offset}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + chapters: (data.items || []).map((ch: any) => ({ + id: ch.id, + name: ch.name, + chapter_number: ch.chapter_number || 0, + duration_ms: ch.duration_ms || 0, + image_url: ch.images?.[0]?.url || null, + external_url: ch.external_urls?.spotify || '', + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + chapters: { type: 'json', description: 'List of chapters' }, + total: { type: 'number', description: 'Total chapters' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_audiobooks.ts b/apps/sim/tools/spotify/get_audiobooks.ts new file mode 100644 index 0000000000..3e5519b36d --- /dev/null +++ b/apps/sim/tools/spotify/get_audiobooks.ts @@ -0,0 +1,87 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetAudiobooksParams { + accessToken: string + audiobookIds: string + market?: string +} + +interface SpotifyGetAudiobooksResponse extends ToolResponse { + output: { + audiobooks: Array<{ + id: string + name: string + authors: Array<{ name: string }> + total_chapters: number + image_url: string | null + external_url: string + }> + } +} + +export const spotifyGetAudiobooksTool: ToolConfig< + SpotifyGetAudiobooksParams, + SpotifyGetAudiobooksResponse +> = { + id: 'spotify_get_audiobooks', + name: 'Spotify Get Multiple Audiobooks', + description: 'Get details for multiple audiobooks.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + audiobookIds: { + type: 'string', + required: true, + description: 'Comma-separated audiobook IDs (max 50)', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const ids = params.audiobookIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + let url = `https://api.spotify.com/v1/audiobooks?ids=${ids}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + audiobooks: (data.audiobooks || []).map((book: any) => ({ + id: book.id, + name: book.name, + authors: book.authors || [], + total_chapters: book.total_chapters || 0, + image_url: book.images?.[0]?.url || null, + external_url: book.external_urls?.spotify || '', + })), + }, + } + }, + + outputs: { + audiobooks: { type: 'json', description: 'List of audiobooks' }, + }, +} diff --git a/apps/sim/tools/spotify/get_categories.ts b/apps/sim/tools/spotify/get_categories.ts new file mode 100644 index 0000000000..4a153e37a1 --- /dev/null +++ b/apps/sim/tools/spotify/get_categories.ts @@ -0,0 +1,82 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetCategoriesParams, SpotifyGetCategoriesResponse } from './types' + +export const spotifyGetCategoriesTool: ToolConfig< + SpotifyGetCategoriesParams, + SpotifyGetCategoriesResponse +> = { + id: 'spotify_get_categories', + name: 'Spotify Get Categories', + description: 'Get a list of browse categories used to tag items in Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + country: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code (e.g., "US", "GB")', + }, + locale: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Locale code (e.g., "en_US", "es_MX")', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of categories to return (1-50)', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + let url = `https://api.spotify.com/v1/browse/categories?limit=${limit}` + if (params.country) { + url += `&country=${params.country}` + } + if (params.locale) { + url += `&locale=${params.locale}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const categories = (data.categories?.items || []).map((category: any) => ({ + id: category.id, + name: category.name, + icon_url: category.icons?.[0]?.url || null, + })) + + return { + success: true, + output: { + categories, + total: data.categories?.total || 0, + }, + } + }, + + outputs: { + categories: { type: 'json', description: 'List of browse categories' }, + total: { type: 'number', description: 'Total number of categories' }, + }, +} diff --git a/apps/sim/tools/spotify/get_current_user.ts b/apps/sim/tools/spotify/get_current_user.ts new file mode 100644 index 0000000000..a9d95917fd --- /dev/null +++ b/apps/sim/tools/spotify/get_current_user.ts @@ -0,0 +1,58 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetCurrentUserParams, SpotifyGetCurrentUserResponse } from './types' + +export const spotifyGetCurrentUserTool: ToolConfig< + SpotifyGetCurrentUserParams, + SpotifyGetCurrentUserResponse +> = { + id: 'spotify_get_current_user', + name: 'Spotify Get Current User', + description: "Get the current user's Spotify profile information.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private', 'user-read-email'], + }, + + params: {}, + + request: { + url: () => 'https://api.spotify.com/v1/me', + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const user = await response.json() + + return { + success: true, + output: { + id: user.id, + display_name: user.display_name || '', + email: user.email || null, + country: user.country || null, + product: user.product || null, + followers: user.followers?.total || 0, + image_url: user.images?.[0]?.url || null, + external_url: user.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify user ID' }, + display_name: { type: 'string', description: 'Display name' }, + email: { type: 'string', description: 'Email address', optional: true }, + country: { type: 'string', description: 'Country code', optional: true }, + product: { type: 'string', description: 'Subscription level (free, premium)', optional: true }, + followers: { type: 'number', description: 'Number of followers' }, + image_url: { type: 'string', description: 'Profile image URL', optional: true }, + external_url: { type: 'string', description: 'Spotify profile URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_currently_playing.ts b/apps/sim/tools/spotify/get_currently_playing.ts new file mode 100644 index 0000000000..0a679c268d --- /dev/null +++ b/apps/sim/tools/spotify/get_currently_playing.ts @@ -0,0 +1,108 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetCurrentlyPlayingParams { + accessToken: string + market?: string +} + +interface SpotifyGetCurrentlyPlayingResponse extends ToolResponse { + output: { + is_playing: boolean + progress_ms: number | null + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + external_url: string + } | null + } +} + +export const spotifyGetCurrentlyPlayingTool: ToolConfig< + SpotifyGetCurrentlyPlayingParams, + SpotifyGetCurrentlyPlayingResponse +> = { + id: 'spotify_get_currently_playing', + name: 'Spotify Get Currently Playing', + description: "Get the user's currently playing track.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-currently-playing'], + }, + + params: { + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player/currently-playing' + if (params.market) { + url += `?market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + if (response.status === 204) { + return { + success: true, + output: { + is_playing: false, + progress_ms: null, + track: null, + }, + } + } + + const data = await response.json() + + return { + success: true, + output: { + is_playing: data.is_playing || false, + progress_ms: data.progress_ms || null, + track: data.item + ? { + id: data.item.id, + name: data.item.name, + artists: data.item.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: data.item.album?.id || '', + name: data.item.album?.name || '', + image_url: data.item.album?.images?.[0]?.url || null, + }, + duration_ms: data.item.duration_ms, + external_url: data.item.external_urls?.spotify || '', + } + : null, + }, + } + }, + + outputs: { + is_playing: { type: 'boolean', description: 'Whether playback is active' }, + progress_ms: { type: 'number', description: 'Current position in track (ms)', optional: true }, + track: { type: 'json', description: 'Currently playing track', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_devices.ts b/apps/sim/tools/spotify/get_devices.ts new file mode 100644 index 0000000000..ff8048a6d9 --- /dev/null +++ b/apps/sim/tools/spotify/get_devices.ts @@ -0,0 +1,67 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetDevicesParams, SpotifyGetDevicesResponse } from './types' + +export const spotifyGetDevicesTool: ToolConfig = + { + id: 'spotify_get_devices', + name: 'Spotify Get Devices', + description: "Get the user's available Spotify playback devices.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-state'], + }, + + params: {}, + + request: { + url: () => 'https://api.spotify.com/v1/me/player/devices', + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const devices = (data.devices || []).map((device: any) => ({ + id: device.id, + is_active: device.is_active, + is_private_session: device.is_private_session, + is_restricted: device.is_restricted, + name: device.name, + type: device.type, + volume_percent: device.volume_percent, + })) + + return { + success: true, + output: { + devices, + }, + } + }, + + outputs: { + devices: { + type: 'array', + description: 'Available playback devices', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Device ID' }, + is_active: { type: 'boolean', description: 'Whether device is active' }, + is_private_session: { type: 'boolean', description: 'Whether in private session' }, + is_restricted: { type: 'boolean', description: 'Whether device is restricted' }, + name: { type: 'string', description: 'Device name' }, + type: { type: 'string', description: 'Device type (Computer, Smartphone, etc.)' }, + volume_percent: { type: 'number', description: 'Current volume (0-100)' }, + }, + }, + }, + }, + } diff --git a/apps/sim/tools/spotify/get_episode.ts b/apps/sim/tools/spotify/get_episode.ts new file mode 100644 index 0000000000..c6a0e373c1 --- /dev/null +++ b/apps/sim/tools/spotify/get_episode.ts @@ -0,0 +1,94 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetEpisodeParams { + accessToken: string + episodeId: string + market?: string +} + +interface SpotifyGetEpisodeResponse extends ToolResponse { + output: { + id: string + name: string + description: string + duration_ms: number + release_date: string + explicit: boolean + show: { id: string; name: string; publisher: string } + image_url: string | null + external_url: string + } +} + +export const spotifyGetEpisodeTool: ToolConfig = + { + id: 'spotify_get_episode', + name: 'Spotify Get Episode', + description: 'Get details for a podcast episode.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + episodeId: { + type: 'string', + required: true, + description: 'The Spotify episode ID', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/episodes/${params.episodeId}` + if (params.market) url += `?market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const ep = await response.json() + return { + success: true, + output: { + id: ep.id, + name: ep.name, + description: ep.description || '', + duration_ms: ep.duration_ms || 0, + release_date: ep.release_date || '', + explicit: ep.explicit || false, + show: { + id: ep.show?.id || '', + name: ep.show?.name || '', + publisher: ep.show?.publisher || '', + }, + image_url: ep.images?.[0]?.url || null, + external_url: ep.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Episode ID' }, + name: { type: 'string', description: 'Episode name' }, + description: { type: 'string', description: 'Episode description' }, + duration_ms: { type: 'number', description: 'Duration in ms' }, + release_date: { type: 'string', description: 'Release date' }, + explicit: { type: 'boolean', description: 'Contains explicit content' }, + show: { type: 'json', description: 'Parent show info' }, + image_url: { type: 'string', description: 'Cover image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + } diff --git a/apps/sim/tools/spotify/get_episodes.ts b/apps/sim/tools/spotify/get_episodes.ts new file mode 100644 index 0000000000..63555f0eec --- /dev/null +++ b/apps/sim/tools/spotify/get_episodes.ts @@ -0,0 +1,91 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetEpisodesParams { + accessToken: string + episodeIds: string + market?: string +} + +interface SpotifyGetEpisodesResponse extends ToolResponse { + output: { + episodes: Array<{ + id: string + name: string + description: string + duration_ms: number + release_date: string + show: { id: string; name: string } + image_url: string | null + external_url: string + }> + } +} + +export const spotifyGetEpisodesTool: ToolConfig< + SpotifyGetEpisodesParams, + SpotifyGetEpisodesResponse +> = { + id: 'spotify_get_episodes', + name: 'Spotify Get Multiple Episodes', + description: 'Get details for multiple podcast episodes.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + episodeIds: { + type: 'string', + required: true, + description: 'Comma-separated episode IDs (max 50)', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const ids = params.episodeIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + let url = `https://api.spotify.com/v1/episodes?ids=${ids}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + episodes: (data.episodes || []).map((ep: any) => ({ + id: ep.id, + name: ep.name, + description: ep.description || '', + duration_ms: ep.duration_ms || 0, + release_date: ep.release_date || '', + show: { id: ep.show?.id || '', name: ep.show?.name || '' }, + image_url: ep.images?.[0]?.url || null, + external_url: ep.external_urls?.spotify || '', + })), + }, + } + }, + + outputs: { + episodes: { type: 'json', description: 'List of episodes' }, + }, +} diff --git a/apps/sim/tools/spotify/get_followed_artists.ts b/apps/sim/tools/spotify/get_followed_artists.ts new file mode 100644 index 0000000000..1cbdaea15d --- /dev/null +++ b/apps/sim/tools/spotify/get_followed_artists.ts @@ -0,0 +1,100 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetFollowedArtistsParams { + accessToken: string + limit?: number + after?: string +} + +interface SpotifyGetFollowedArtistsResponse extends ToolResponse { + output: { + artists: Array<{ + id: string + name: string + genres: string[] + popularity: number + followers: number + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +export const spotifyGetFollowedArtistsTool: ToolConfig< + SpotifyGetFollowedArtistsParams, + SpotifyGetFollowedArtistsResponse +> = { + id: 'spotify_get_followed_artists', + name: 'Spotify Get Followed Artists', + description: "Get the user's followed artists.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-follow-read'], + }, + + params: { + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of artists to return (1-50)', + }, + after: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Cursor for pagination (last artist ID from previous request)', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + let url = `https://api.spotify.com/v1/me/following?type=artist&limit=${limit}` + if (params.after) { + url += `&after=${params.after}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const artists = (data.artists?.items || []).map((artist: any) => ({ + id: artist.id, + name: artist.name, + genres: artist.genres || [], + popularity: artist.popularity || 0, + followers: artist.followers?.total || 0, + image_url: artist.images?.[0]?.url || null, + external_url: artist.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + artists, + total: data.artists?.total || 0, + next: data.artists?.cursors?.after || null, + }, + } + }, + + outputs: { + artists: { type: 'json', description: 'List of followed artists' }, + total: { type: 'number', description: 'Total number of followed artists' }, + next: { type: 'string', description: 'Cursor for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_markets.ts b/apps/sim/tools/spotify/get_markets.ts new file mode 100644 index 0000000000..5e29c36149 --- /dev/null +++ b/apps/sim/tools/spotify/get_markets.ts @@ -0,0 +1,47 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetMarketsParams { + accessToken: string +} + +interface SpotifyGetMarketsResponse extends ToolResponse { + output: { + markets: string[] + } +} + +export const spotifyGetMarketsTool: ToolConfig = + { + id: 'spotify_get_markets', + name: 'Spotify Get Available Markets', + description: 'Get the list of markets where Spotify is available.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: {}, + + request: { + url: () => 'https://api.spotify.com/v1/markets', + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { markets: data.markets || [] }, + } + }, + + outputs: { + markets: { type: 'json', description: 'List of ISO country codes' }, + }, + } diff --git a/apps/sim/tools/spotify/get_new_releases.ts b/apps/sim/tools/spotify/get_new_releases.ts new file mode 100644 index 0000000000..9f2c10a400 --- /dev/null +++ b/apps/sim/tools/spotify/get_new_releases.ts @@ -0,0 +1,88 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetNewReleasesParams, SpotifyGetNewReleasesResponse } from './types' + +export const spotifyGetNewReleasesTool: ToolConfig< + SpotifyGetNewReleasesParams, + SpotifyGetNewReleasesResponse +> = { + id: 'spotify_get_new_releases', + name: 'Spotify Get New Releases', + description: 'Get a list of new album releases featured in Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + country: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code (e.g., "US", "GB")', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of releases to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of first release to return', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/browse/new-releases?limit=${limit}&offset=${offset}` + if (params.country) { + url += `&country=${params.country}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const albums = (data.albums?.items || []).map((album: any) => ({ + id: album.id, + name: album.name, + artists: album.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + release_date: album.release_date, + total_tracks: album.total_tracks, + album_type: album.album_type, + image_url: album.images?.[0]?.url || null, + external_url: album.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + albums, + total: data.albums?.total || 0, + next: data.albums?.next || null, + }, + } + }, + + outputs: { + albums: { type: 'json', description: 'List of new releases' }, + total: { type: 'number', description: 'Total number of new releases' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_playback_state.ts b/apps/sim/tools/spotify/get_playback_state.ts new file mode 100644 index 0000000000..b0e9c2152f --- /dev/null +++ b/apps/sim/tools/spotify/get_playback_state.ts @@ -0,0 +1,103 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetPlaybackStateParams, SpotifyGetPlaybackStateResponse } from './types' + +export const spotifyGetPlaybackStateTool: ToolConfig< + SpotifyGetPlaybackStateParams, + SpotifyGetPlaybackStateResponse +> = { + id: 'spotify_get_playback_state', + name: 'Spotify Get Playback State', + description: 'Get the current playback state including device, track, and progress.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-state'], + }, + + params: { + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player' + if (params.market) { + url += `?market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + if (response.status === 204) { + return { + success: true, + output: { + is_playing: false, + device: null, + progress_ms: null, + currently_playing_type: 'unknown', + shuffle_state: false, + repeat_state: 'off', + track: null, + }, + } + } + + const data = await response.json() + + return { + success: true, + output: { + is_playing: data.is_playing || false, + device: data.device + ? { + id: data.device.id, + name: data.device.name, + type: data.device.type, + volume_percent: data.device.volume_percent, + } + : null, + progress_ms: data.progress_ms, + currently_playing_type: data.currently_playing_type || 'unknown', + shuffle_state: data.shuffle_state || false, + repeat_state: data.repeat_state || 'off', + track: data.item + ? { + id: data.item.id, + name: data.item.name, + artists: data.item.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: data.item.album?.id || '', + name: data.item.album?.name || '', + image_url: data.item.album?.images?.[0]?.url || null, + }, + duration_ms: data.item.duration_ms, + } + : null, + }, + } + }, + + outputs: { + is_playing: { type: 'boolean', description: 'Whether playback is active' }, + device: { type: 'object', description: 'Active device information', optional: true }, + progress_ms: { type: 'number', description: 'Progress in milliseconds', optional: true }, + currently_playing_type: { type: 'string', description: 'Type of content playing' }, + shuffle_state: { type: 'boolean', description: 'Whether shuffle is enabled' }, + repeat_state: { type: 'string', description: 'Repeat mode (off, track, context)' }, + track: { type: 'object', description: 'Currently playing track', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_playlist.ts b/apps/sim/tools/spotify/get_playlist.ts new file mode 100644 index 0000000000..b1b0a84ab9 --- /dev/null +++ b/apps/sim/tools/spotify/get_playlist.ts @@ -0,0 +1,83 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetPlaylistParams, SpotifyGetPlaylistResponse } from './types' + +export const spotifyGetPlaylistTool: ToolConfig< + SpotifyGetPlaylistParams, + SpotifyGetPlaylistResponse +> = { + id: 'spotify_get_playlist', + name: 'Spotify Get Playlist', + description: 'Get detailed information about a playlist on Spotify by its ID.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + playlistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the playlist', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code for track availability', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/playlists/${params.playlistId}` + if (params.market) { + url += `?market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const playlist = await response.json() + + return { + success: true, + output: { + id: playlist.id, + name: playlist.name, + description: playlist.description, + public: playlist.public, + collaborative: playlist.collaborative, + owner: { + id: playlist.owner?.id || '', + display_name: playlist.owner?.display_name || '', + }, + image_url: playlist.images?.[0]?.url || null, + total_tracks: playlist.tracks?.total || 0, + snapshot_id: playlist.snapshot_id, + external_url: playlist.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify playlist ID' }, + name: { type: 'string', description: 'Playlist name' }, + description: { type: 'string', description: 'Playlist description', optional: true }, + public: { type: 'boolean', description: 'Whether the playlist is public' }, + collaborative: { type: 'boolean', description: 'Whether the playlist is collaborative' }, + owner: { type: 'object', description: 'Playlist owner information' }, + image_url: { type: 'string', description: 'Playlist cover image URL', optional: true }, + total_tracks: { type: 'number', description: 'Total number of tracks' }, + snapshot_id: { type: 'string', description: 'Playlist snapshot ID for versioning' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_playlist_cover.ts b/apps/sim/tools/spotify/get_playlist_cover.ts new file mode 100644 index 0000000000..9650d5affa --- /dev/null +++ b/apps/sim/tools/spotify/get_playlist_cover.ts @@ -0,0 +1,66 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetPlaylistCoverParams { + accessToken: string + playlistId: string +} + +interface SpotifyGetPlaylistCoverResponse extends ToolResponse { + output: { + images: Array<{ + url: string + width: number | null + height: number | null + }> + } +} + +export const spotifyGetPlaylistCoverTool: ToolConfig< + SpotifyGetPlaylistCoverParams, + SpotifyGetPlaylistCoverResponse +> = { + id: 'spotify_get_playlist_cover', + name: 'Spotify Get Playlist Cover', + description: "Get a playlist's cover image.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-read-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/images`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const images = await response.json() + return { + success: true, + output: { + images: (images || []).map((img: any) => ({ + url: img.url, + width: img.width || null, + height: img.height || null, + })), + }, + } + }, + + outputs: { + images: { type: 'json', description: 'List of cover images' }, + }, +} diff --git a/apps/sim/tools/spotify/get_playlist_tracks.ts b/apps/sim/tools/spotify/get_playlist_tracks.ts new file mode 100644 index 0000000000..8bd423efd0 --- /dev/null +++ b/apps/sim/tools/spotify/get_playlist_tracks.ts @@ -0,0 +1,113 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetPlaylistTracksParams, SpotifyGetPlaylistTracksResponse } from './types' + +export const spotifyGetPlaylistTracksTool: ToolConfig< + SpotifyGetPlaylistTracksParams, + SpotifyGetPlaylistTracksResponse +> = { + id: 'spotify_get_playlist_tracks', + name: 'Spotify Get Playlist Tracks', + description: 'Get the tracks in a Spotify playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + playlistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the playlist', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 50, + description: 'Maximum number of tracks to return (1-100)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first track to return', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code for track availability', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 50, 1), 100) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/playlists/${params.playlistId}/tracks?limit=${limit}&offset=${offset}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.items || []) + .filter((item: any) => item.track !== null) + .map((item: any) => ({ + added_at: item.added_at, + added_by: item.added_by?.id || '', + track: { + id: item.track.id, + name: item.track.name, + artists: item.track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: item.track.album?.id || '', + name: item.track.album?.name || '', + image_url: item.track.album?.images?.[0]?.url || null, + }, + duration_ms: item.track.duration_ms, + popularity: item.track.popularity, + external_url: item.track.external_urls?.spotify || '', + }, + })) + + return { + success: true, + output: { + tracks, + total: data.total || tracks.length, + next: data.next || null, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: 'List of tracks in the playlist', + items: { + type: 'object', + properties: { + added_at: { type: 'string', description: 'When the track was added' }, + added_by: { type: 'string', description: 'User ID who added the track' }, + track: { type: 'object', description: 'Track information' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of tracks in playlist' }, + next: { type: 'string', description: 'URL for next page of results', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_queue.ts b/apps/sim/tools/spotify/get_queue.ts new file mode 100644 index 0000000000..ef36bd79d4 --- /dev/null +++ b/apps/sim/tools/spotify/get_queue.ts @@ -0,0 +1,85 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetQueueParams { + accessToken: string +} + +interface SpotifyGetQueueResponse extends ToolResponse { + output: { + currently_playing: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + } | null + queue: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + }> + } +} + +export const spotifyGetQueueTool: ToolConfig = { + id: 'spotify_get_queue', + name: 'Spotify Get Queue', + description: "Get the user's playback queue.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-state'], + }, + + params: {}, + + request: { + url: () => 'https://api.spotify.com/v1/me/player/queue', + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const formatTrack = (track: any) => ({ + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: track.album?.id || '', + name: track.album?.name || '', + image_url: track.album?.images?.[0]?.url || null, + }, + duration_ms: track.duration_ms, + }) + + return { + success: true, + output: { + currently_playing: data.currently_playing ? formatTrack(data.currently_playing) : null, + queue: (data.queue || []).map(formatTrack), + }, + } + }, + + outputs: { + currently_playing: { type: 'json', description: 'Currently playing track', optional: true }, + queue: { type: 'json', description: 'Upcoming tracks in queue' }, + }, +} diff --git a/apps/sim/tools/spotify/get_recently_played.ts b/apps/sim/tools/spotify/get_recently_played.ts new file mode 100644 index 0000000000..51bd7f976d --- /dev/null +++ b/apps/sim/tools/spotify/get_recently_played.ts @@ -0,0 +1,102 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetRecentlyPlayedParams, SpotifyGetRecentlyPlayedResponse } from './types' + +export const spotifyGetRecentlyPlayedTool: ToolConfig< + SpotifyGetRecentlyPlayedParams, + SpotifyGetRecentlyPlayedResponse +> = { + id: 'spotify_get_recently_played', + name: 'Spotify Get Recently Played', + description: "Get the user's recently played tracks.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-recently-played'], + }, + + params: { + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of tracks to return (1-50)', + }, + after: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Unix timestamp in milliseconds. Returns items after this cursor.', + }, + before: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Unix timestamp in milliseconds. Returns items before this cursor.', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + let url = `https://api.spotify.com/v1/me/player/recently-played?limit=${limit}` + if (params.after) { + url += `&after=${params.after}` + } + if (params.before) { + url += `&before=${params.before}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const items = (data.items || []).map((item: any) => ({ + played_at: item.played_at, + track: { + id: item.track.id, + name: item.track.name, + artists: item.track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: item.track.album?.id || '', + name: item.track.album?.name || '', + image_url: item.track.album?.images?.[0]?.url || null, + }, + duration_ms: item.track.duration_ms, + external_url: item.track.external_urls?.spotify || '', + }, + })) + + return { + success: true, + output: { + items, + next: data.next || null, + }, + } + }, + + outputs: { + items: { + type: 'array', + description: 'Recently played tracks', + items: { + type: 'object', + properties: { + played_at: { type: 'string', description: 'When the track was played' }, + track: { type: 'object', description: 'Track information' }, + }, + }, + }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_saved_albums.ts b/apps/sim/tools/spotify/get_saved_albums.ts new file mode 100644 index 0000000000..d35023501a --- /dev/null +++ b/apps/sim/tools/spotify/get_saved_albums.ts @@ -0,0 +1,106 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetSavedAlbumsParams { + accessToken: string + limit?: number + offset?: number + market?: string +} + +interface SpotifyGetSavedAlbumsResponse extends ToolResponse { + output: { + albums: Array<{ + added_at: string + album: { + id: string + name: string + artists: Array<{ id: string; name: string }> + total_tracks: number + release_date: string + image_url: string | null + external_url: string + } + }> + total: number + next: string | null + } +} + +export const spotifyGetSavedAlbumsTool: ToolConfig< + SpotifyGetSavedAlbumsParams, + SpotifyGetSavedAlbumsResponse +> = { + id: 'spotify_get_saved_albums', + name: 'Spotify Get Saved Albums', + description: "Get the user's saved albums.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of albums to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first album to return', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/me/albums?limit=${limit}&offset=${offset}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + albums: (data.items || []).map((item: any) => ({ + added_at: item.added_at, + album: { + id: item.album.id, + name: item.album.name, + artists: item.album.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + total_tracks: item.album.total_tracks, + release_date: item.album.release_date, + image_url: item.album.images?.[0]?.url || null, + external_url: item.album.external_urls?.spotify || '', + }, + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + albums: { type: 'json', description: 'List of saved albums' }, + total: { type: 'number', description: 'Total saved albums' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_saved_audiobooks.ts b/apps/sim/tools/spotify/get_saved_audiobooks.ts new file mode 100644 index 0000000000..fcb7b83deb --- /dev/null +++ b/apps/sim/tools/spotify/get_saved_audiobooks.ts @@ -0,0 +1,97 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetSavedAudiobooksParams { + accessToken: string + limit?: number + offset?: number +} + +interface SpotifyGetSavedAudiobooksResponse extends ToolResponse { + output: { + audiobooks: Array<{ + added_at: string + audiobook: { + id: string + name: string + authors: Array<{ name: string }> + total_chapters: number + image_url: string | null + external_url: string + } + }> + total: number + next: string | null + } +} + +export const spotifyGetSavedAudiobooksTool: ToolConfig< + SpotifyGetSavedAudiobooksParams, + SpotifyGetSavedAudiobooksResponse +> = { + id: 'spotify_get_saved_audiobooks', + name: 'Spotify Get Saved Audiobooks', + description: "Get the user's saved audiobooks.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of audiobooks to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first audiobook to return', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + return `https://api.spotify.com/v1/me/audiobooks?limit=${limit}&offset=${offset}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + audiobooks: (data.items || []).map((item: any) => ({ + added_at: item.added_at, + audiobook: { + id: item.audiobook?.id || item.id, + name: item.audiobook?.name || item.name, + authors: item.audiobook?.authors || item.authors || [], + total_chapters: item.audiobook?.total_chapters || item.total_chapters || 0, + image_url: item.audiobook?.images?.[0]?.url || item.images?.[0]?.url || null, + external_url: + item.audiobook?.external_urls?.spotify || item.external_urls?.spotify || '', + }, + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + audiobooks: { type: 'json', description: 'List of saved audiobooks' }, + total: { type: 'number', description: 'Total saved audiobooks' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_saved_episodes.ts b/apps/sim/tools/spotify/get_saved_episodes.ts new file mode 100644 index 0000000000..a9dec882e5 --- /dev/null +++ b/apps/sim/tools/spotify/get_saved_episodes.ts @@ -0,0 +1,106 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetSavedEpisodesParams { + accessToken: string + limit?: number + offset?: number + market?: string +} + +interface SpotifyGetSavedEpisodesResponse extends ToolResponse { + output: { + episodes: Array<{ + added_at: string + episode: { + id: string + name: string + duration_ms: number + release_date: string + show: { id: string; name: string } + image_url: string | null + external_url: string + } + }> + total: number + next: string | null + } +} + +export const spotifyGetSavedEpisodesTool: ToolConfig< + SpotifyGetSavedEpisodesParams, + SpotifyGetSavedEpisodesResponse +> = { + id: 'spotify_get_saved_episodes', + name: 'Spotify Get Saved Episodes', + description: "Get the user's saved podcast episodes.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read', 'user-read-playback-position'], + }, + + params: { + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of episodes to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first episode to return', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/me/episodes?limit=${limit}&offset=${offset}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + episodes: (data.items || []).map((item: any) => ({ + added_at: item.added_at, + episode: { + id: item.episode.id, + name: item.episode.name, + duration_ms: item.episode.duration_ms || 0, + release_date: item.episode.release_date || '', + show: { id: item.episode.show?.id || '', name: item.episode.show?.name || '' }, + image_url: item.episode.images?.[0]?.url || null, + external_url: item.episode.external_urls?.spotify || '', + }, + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + episodes: { type: 'json', description: 'List of saved episodes' }, + total: { type: 'number', description: 'Total saved episodes' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_saved_shows.ts b/apps/sim/tools/spotify/get_saved_shows.ts new file mode 100644 index 0000000000..e0b9cf6f85 --- /dev/null +++ b/apps/sim/tools/spotify/get_saved_shows.ts @@ -0,0 +1,96 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetSavedShowsParams { + accessToken: string + limit?: number + offset?: number +} + +interface SpotifyGetSavedShowsResponse extends ToolResponse { + output: { + shows: Array<{ + added_at: string + show: { + id: string + name: string + publisher: string + total_episodes: number + image_url: string | null + external_url: string + } + }> + total: number + next: string | null + } +} + +export const spotifyGetSavedShowsTool: ToolConfig< + SpotifyGetSavedShowsParams, + SpotifyGetSavedShowsResponse +> = { + id: 'spotify_get_saved_shows', + name: 'Spotify Get Saved Shows', + description: "Get the user's saved podcast shows.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of shows to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first show to return', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + return `https://api.spotify.com/v1/me/shows?limit=${limit}&offset=${offset}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + shows: (data.items || []).map((item: any) => ({ + added_at: item.added_at, + show: { + id: item.show.id, + name: item.show.name, + publisher: item.show.publisher || '', + total_episodes: item.show.total_episodes || 0, + image_url: item.show.images?.[0]?.url || null, + external_url: item.show.external_urls?.spotify || '', + }, + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + shows: { type: 'json', description: 'List of saved shows' }, + total: { type: 'number', description: 'Total saved shows' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_saved_tracks.ts b/apps/sim/tools/spotify/get_saved_tracks.ts new file mode 100644 index 0000000000..61f07f1a73 --- /dev/null +++ b/apps/sim/tools/spotify/get_saved_tracks.ts @@ -0,0 +1,104 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetSavedTracksParams, SpotifyGetSavedTracksResponse } from './types' + +export const spotifyGetSavedTracksTool: ToolConfig< + SpotifyGetSavedTracksParams, + SpotifyGetSavedTracksResponse +> = { + id: 'spotify_get_saved_tracks', + name: 'Spotify Get Saved Tracks', + description: "Get the current user's saved/liked tracks from their library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-read'], + }, + + params: { + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of tracks to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first track to return', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/me/tracks?limit=${limit}&offset=${offset}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.items || []).map((item: any) => ({ + added_at: item.added_at, + track: { + id: item.track.id, + name: item.track.name, + artists: item.track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: item.track.album?.id || '', + name: item.track.album?.name || '', + image_url: item.track.album?.images?.[0]?.url || null, + }, + duration_ms: item.track.duration_ms, + popularity: item.track.popularity, + external_url: item.track.external_urls?.spotify || '', + }, + })) + + return { + success: true, + output: { + tracks, + total: data.total || tracks.length, + next: data.next || null, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: "User's saved tracks", + items: { + type: 'object', + properties: { + added_at: { type: 'string', description: 'When the track was saved' }, + track: { type: 'object', description: 'Track information' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of saved tracks' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_show.ts b/apps/sim/tools/spotify/get_show.ts new file mode 100644 index 0000000000..66e58445a7 --- /dev/null +++ b/apps/sim/tools/spotify/get_show.ts @@ -0,0 +1,89 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetShowParams { + accessToken: string + showId: string + market?: string +} + +interface SpotifyGetShowResponse extends ToolResponse { + output: { + id: string + name: string + description: string + publisher: string + total_episodes: number + explicit: boolean + languages: string[] + image_url: string | null + external_url: string + } +} + +export const spotifyGetShowTool: ToolConfig = { + id: 'spotify_get_show', + name: 'Spotify Get Show', + description: 'Get details for a podcast show.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + showId: { + type: 'string', + required: true, + description: 'The Spotify show ID', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/shows/${params.showId}` + if (params.market) url += `?market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const show = await response.json() + return { + success: true, + output: { + id: show.id, + name: show.name, + description: show.description || '', + publisher: show.publisher || '', + total_episodes: show.total_episodes || 0, + explicit: show.explicit || false, + languages: show.languages || [], + image_url: show.images?.[0]?.url || null, + external_url: show.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Show ID' }, + name: { type: 'string', description: 'Show name' }, + description: { type: 'string', description: 'Show description' }, + publisher: { type: 'string', description: 'Publisher name' }, + total_episodes: { type: 'number', description: 'Total episodes' }, + explicit: { type: 'boolean', description: 'Contains explicit content' }, + languages: { type: 'json', description: 'Languages' }, + image_url: { type: 'string', description: 'Cover image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/get_show_episodes.ts b/apps/sim/tools/spotify/get_show_episodes.ts new file mode 100644 index 0000000000..9c290cd384 --- /dev/null +++ b/apps/sim/tools/spotify/get_show_episodes.ts @@ -0,0 +1,106 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetShowEpisodesParams { + accessToken: string + showId: string + limit?: number + offset?: number + market?: string +} + +interface SpotifyGetShowEpisodesResponse extends ToolResponse { + output: { + episodes: Array<{ + id: string + name: string + description: string + duration_ms: number + release_date: string + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +export const spotifyGetShowEpisodesTool: ToolConfig< + SpotifyGetShowEpisodesParams, + SpotifyGetShowEpisodesResponse +> = { + id: 'spotify_get_show_episodes', + name: 'Spotify Get Show Episodes', + description: 'Get episodes from a podcast show.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + showId: { + type: 'string', + required: true, + description: 'The Spotify show ID', + }, + limit: { + type: 'number', + required: false, + default: 20, + description: 'Number of episodes to return (1-50)', + }, + offset: { + type: 'number', + required: false, + default: 0, + description: 'Index of first episode to return', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/shows/${params.showId}/episodes?limit=${limit}&offset=${offset}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + episodes: (data.items || []).map((ep: any) => ({ + id: ep.id, + name: ep.name, + description: ep.description || '', + duration_ms: ep.duration_ms || 0, + release_date: ep.release_date || '', + image_url: ep.images?.[0]?.url || null, + external_url: ep.external_urls?.spotify || '', + })), + total: data.total || 0, + next: data.next || null, + }, + } + }, + + outputs: { + episodes: { type: 'json', description: 'List of episodes' }, + total: { type: 'number', description: 'Total episodes' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_shows.ts b/apps/sim/tools/spotify/get_shows.ts new file mode 100644 index 0000000000..99ff862b65 --- /dev/null +++ b/apps/sim/tools/spotify/get_shows.ts @@ -0,0 +1,84 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetShowsParams { + accessToken: string + showIds: string + market?: string +} + +interface SpotifyGetShowsResponse extends ToolResponse { + output: { + shows: Array<{ + id: string + name: string + publisher: string + total_episodes: number + image_url: string | null + external_url: string + }> + } +} + +export const spotifyGetShowsTool: ToolConfig = { + id: 'spotify_get_shows', + name: 'Spotify Get Multiple Shows', + description: 'Get details for multiple podcast shows.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-playback-position'], + }, + + params: { + showIds: { + type: 'string', + required: true, + description: 'Comma-separated show IDs (max 50)', + }, + market: { + type: 'string', + required: false, + description: 'ISO country code for market', + }, + }, + + request: { + url: (params) => { + const ids = params.showIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + let url = `https://api.spotify.com/v1/shows?ids=${ids}` + if (params.market) url += `&market=${params.market}` + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { + shows: (data.shows || []).map((show: any) => ({ + id: show.id, + name: show.name, + publisher: show.publisher || '', + total_episodes: show.total_episodes || 0, + image_url: show.images?.[0]?.url || null, + external_url: show.external_urls?.spotify || '', + })), + }, + } + }, + + outputs: { + shows: { type: 'json', description: 'List of shows' }, + }, +} diff --git a/apps/sim/tools/spotify/get_top_artists.ts b/apps/sim/tools/spotify/get_top_artists.ts new file mode 100644 index 0000000000..7c8d453f64 --- /dev/null +++ b/apps/sim/tools/spotify/get_top_artists.ts @@ -0,0 +1,100 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetTopArtistsResponse, SpotifyGetTopItemsParams } from './types' + +export const spotifyGetTopArtistsTool: ToolConfig< + SpotifyGetTopItemsParams, + SpotifyGetTopArtistsResponse +> = { + id: 'spotify_get_top_artists', + name: 'Spotify Get Top Artists', + description: "Get the current user's top artists based on listening history.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-top-read'], + }, + + params: { + time_range: { + type: 'string', + required: false, + visibility: 'user-or-llm', + default: 'medium_term', + description: 'Time range: short_term (~4 weeks), medium_term (~6 months), long_term (years)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of artists to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first artist to return', + }, + }, + + request: { + url: (params) => { + const timeRange = params.time_range || 'medium_term' + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + return `https://api.spotify.com/v1/me/top/artists?time_range=${timeRange}&limit=${limit}&offset=${offset}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const artists = (data.items || []).map((artist: any) => ({ + id: artist.id, + name: artist.name, + genres: artist.genres || [], + popularity: artist.popularity, + followers: artist.followers?.total || 0, + image_url: artist.images?.[0]?.url || null, + external_url: artist.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + artists, + total: data.total || artists.length, + next: data.next || null, + }, + } + }, + + outputs: { + artists: { + type: 'array', + description: "User's top artists", + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify artist ID' }, + name: { type: 'string', description: 'Artist name' }, + genres: { type: 'array', description: 'List of genres' }, + popularity: { type: 'number', description: 'Popularity score' }, + followers: { type: 'number', description: 'Number of followers' }, + image_url: { type: 'string', description: 'Artist image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of top artists' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_top_tracks.ts b/apps/sim/tools/spotify/get_top_tracks.ts new file mode 100644 index 0000000000..f63dbc1041 --- /dev/null +++ b/apps/sim/tools/spotify/get_top_tracks.ts @@ -0,0 +1,104 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetTopItemsParams, SpotifyGetTopTracksResponse } from './types' + +export const spotifyGetTopTracksTool: ToolConfig< + SpotifyGetTopItemsParams, + SpotifyGetTopTracksResponse +> = { + id: 'spotify_get_top_tracks', + name: 'Spotify Get Top Tracks', + description: "Get the current user's top tracks based on listening history.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-top-read'], + }, + + params: { + time_range: { + type: 'string', + required: false, + visibility: 'user-or-llm', + default: 'medium_term', + description: 'Time range: short_term (~4 weeks), medium_term (~6 months), long_term (years)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Number of tracks to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first track to return', + }, + }, + + request: { + url: (params) => { + const timeRange = params.time_range || 'medium_term' + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + return `https://api.spotify.com/v1/me/top/tracks?time_range=${timeRange}&limit=${limit}&offset=${offset}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.items || []).map((track: any) => ({ + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: track.album?.id || '', + name: track.album?.name || '', + image_url: track.album?.images?.[0]?.url || null, + }, + duration_ms: track.duration_ms, + popularity: track.popularity, + external_url: track.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + tracks, + total: data.total || tracks.length, + next: data.next || null, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: "User's top tracks", + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify track ID' }, + name: { type: 'string', description: 'Track name' }, + artists: { type: 'array', description: 'List of artists' }, + album: { type: 'object', description: 'Album information' }, + duration_ms: { type: 'number', description: 'Duration in milliseconds' }, + popularity: { type: 'number', description: 'Popularity score' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of top tracks' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_track.ts b/apps/sim/tools/spotify/get_track.ts new file mode 100644 index 0000000000..b6360efa16 --- /dev/null +++ b/apps/sim/tools/spotify/get_track.ts @@ -0,0 +1,81 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetTrackParams, SpotifyGetTrackResponse } from './types' + +export const spotifyGetTrackTool: ToolConfig = { + id: 'spotify_get_track', + name: 'Spotify Get Track', + description: 'Get detailed information about a specific track on Spotify by its ID.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + trackId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the track', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code for track availability', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/tracks/${params.trackId}` + if (params.market) { + url += `?market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const track = await response.json() + + return { + success: true, + output: { + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: track.album?.id || '', + name: track.album?.name || '', + image_url: track.album?.images?.[0]?.url || null, + }, + duration_ms: track.duration_ms, + explicit: track.explicit, + popularity: track.popularity, + preview_url: track.preview_url, + external_url: track.external_urls?.spotify || '', + uri: track.uri, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Spotify track ID' }, + name: { type: 'string', description: 'Track name' }, + artists: { type: 'array', description: 'List of artists' }, + album: { type: 'object', description: 'Album information' }, + duration_ms: { type: 'number', description: 'Track duration in milliseconds' }, + explicit: { type: 'boolean', description: 'Whether the track has explicit content' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + preview_url: { type: 'string', description: 'URL to 30-second preview', optional: true }, + external_url: { type: 'string', description: 'Spotify URL' }, + uri: { type: 'string', description: 'Spotify URI for the track' }, + }, +} diff --git a/apps/sim/tools/spotify/get_tracks.ts b/apps/sim/tools/spotify/get_tracks.ts new file mode 100644 index 0000000000..6c6d3312d7 --- /dev/null +++ b/apps/sim/tools/spotify/get_tracks.ts @@ -0,0 +1,94 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetTracksParams, SpotifyGetTracksResponse } from './types' + +export const spotifyGetTracksTool: ToolConfig = { + id: 'spotify_get_tracks', + name: 'Spotify Get Multiple Tracks', + description: 'Get detailed information about multiple tracks on Spotify by their IDs (up to 50).', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + trackIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated list of Spotify track IDs (max 50)', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code for track availability', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/tracks?ids=${encodeURIComponent(params.trackIds)}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.tracks || []) + .filter((t: any) => t !== null) + .map((track: any) => ({ + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => ({ id: a.id, name: a.name })) || [], + album: { + id: track.album?.id || '', + name: track.album?.name || '', + image_url: track.album?.images?.[0]?.url || null, + }, + duration_ms: track.duration_ms, + explicit: track.explicit, + popularity: track.popularity, + preview_url: track.preview_url, + external_url: track.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + tracks, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: 'List of tracks', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify track ID' }, + name: { type: 'string', description: 'Track name' }, + artists: { type: 'array', description: 'List of artists' }, + album: { type: 'object', description: 'Album information' }, + duration_ms: { type: 'number', description: 'Track duration in milliseconds' }, + explicit: { type: 'boolean', description: 'Whether the track has explicit content' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + preview_url: { type: 'string', description: 'URL to 30-second preview' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/spotify/get_user_playlists.ts b/apps/sim/tools/spotify/get_user_playlists.ts new file mode 100644 index 0000000000..f799e45077 --- /dev/null +++ b/apps/sim/tools/spotify/get_user_playlists.ts @@ -0,0 +1,96 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyGetUserPlaylistsParams, SpotifyGetUserPlaylistsResponse } from './types' + +export const spotifyGetUserPlaylistsTool: ToolConfig< + SpotifyGetUserPlaylistsParams, + SpotifyGetUserPlaylistsResponse +> = { + id: 'spotify_get_user_playlists', + name: 'Spotify Get User Playlists', + description: "Get the current user's playlists on Spotify.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-read-private', 'playlist-read-collaborative'], + }, + + params: { + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Maximum number of playlists to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first playlist to return', + }, + }, + + request: { + url: (params) => { + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + return `https://api.spotify.com/v1/me/playlists?limit=${limit}&offset=${offset}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const playlists = (data.items || []).map((playlist: any) => ({ + id: playlist.id, + name: playlist.name, + description: playlist.description, + public: playlist.public, + collaborative: playlist.collaborative, + owner: playlist.owner?.display_name || '', + total_tracks: playlist.tracks?.total || 0, + image_url: playlist.images?.[0]?.url || null, + external_url: playlist.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + playlists, + total: data.total || playlists.length, + next: data.next || null, + }, + } + }, + + outputs: { + playlists: { + type: 'array', + description: "User's playlists", + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify playlist ID' }, + name: { type: 'string', description: 'Playlist name' }, + description: { type: 'string', description: 'Playlist description' }, + public: { type: 'boolean', description: 'Whether public' }, + collaborative: { type: 'boolean', description: 'Whether collaborative' }, + owner: { type: 'string', description: 'Owner display name' }, + total_tracks: { type: 'number', description: 'Number of tracks' }, + image_url: { type: 'string', description: 'Cover image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of playlists' }, + next: { type: 'string', description: 'URL for next page', optional: true }, + }, +} diff --git a/apps/sim/tools/spotify/get_user_profile.ts b/apps/sim/tools/spotify/get_user_profile.ts new file mode 100644 index 0000000000..43a47930dd --- /dev/null +++ b/apps/sim/tools/spotify/get_user_profile.ts @@ -0,0 +1,70 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyGetUserProfileParams { + accessToken: string + userId: string +} + +interface SpotifyGetUserProfileResponse extends ToolResponse { + output: { + id: string + display_name: string | null + followers: number + image_url: string | null + external_url: string + } +} + +export const spotifyGetUserProfileTool: ToolConfig< + SpotifyGetUserProfileParams, + SpotifyGetUserProfileResponse +> = { + id: 'spotify_get_user_profile', + name: 'Spotify Get User Profile', + description: "Get a user's public profile.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-read-private'], + }, + + params: { + userId: { + type: 'string', + required: true, + description: 'The Spotify user ID', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/users/${params.userId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (response): Promise => { + const user = await response.json() + return { + success: true, + output: { + id: user.id, + display_name: user.display_name || null, + followers: user.followers?.total || 0, + image_url: user.images?.[0]?.url || null, + external_url: user.external_urls?.spotify || '', + }, + } + }, + + outputs: { + id: { type: 'string', description: 'User ID' }, + display_name: { type: 'string', description: 'Display name' }, + followers: { type: 'number', description: 'Number of followers' }, + image_url: { type: 'string', description: 'Profile image URL' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, +} diff --git a/apps/sim/tools/spotify/index.ts b/apps/sim/tools/spotify/index.ts new file mode 100644 index 0000000000..cc171a4d72 --- /dev/null +++ b/apps/sim/tools/spotify/index.ts @@ -0,0 +1,92 @@ +// Search & Discovery + +export { spotifyAddPlaylistCoverTool } from './add_playlist_cover' +// Player Controls +export { spotifyAddToQueueTool } from './add_to_queue' +export { spotifyAddTracksToPlaylistTool } from './add_tracks_to_playlist' +export { spotifyCheckFollowingTool } from './check_following' +export { spotifyCheckPlaylistFollowersTool } from './check_playlist_followers' +export { spotifyCheckSavedAlbumsTool } from './check_saved_albums' +export { spotifyCheckSavedAudiobooksTool } from './check_saved_audiobooks' +export { spotifyCheckSavedEpisodesTool } from './check_saved_episodes' +export { spotifyCheckSavedShowsTool } from './check_saved_shows' +export { spotifyCheckSavedTracksTool } from './check_saved_tracks' +export { spotifyCreatePlaylistTool } from './create_playlist' +export { spotifyFollowArtistsTool } from './follow_artists' +export { spotifyFollowPlaylistTool } from './follow_playlist' +// Albums +export { spotifyGetAlbumTool } from './get_album' +export { spotifyGetAlbumTracksTool } from './get_album_tracks' +export { spotifyGetAlbumsTool } from './get_albums' +// Artists +export { spotifyGetArtistTool } from './get_artist' +export { spotifyGetArtistAlbumsTool } from './get_artist_albums' +export { spotifyGetArtistTopTracksTool } from './get_artist_top_tracks' +export { spotifyGetArtistsTool } from './get_artists' +// Audiobooks +export { spotifyGetAudiobookTool } from './get_audiobook' +export { spotifyGetAudiobookChaptersTool } from './get_audiobook_chapters' +export { spotifyGetAudiobooksTool } from './get_audiobooks' +export { spotifyGetCategoriesTool } from './get_categories' +// User Profile & Library +export { spotifyGetCurrentUserTool } from './get_current_user' +export { spotifyGetCurrentlyPlayingTool } from './get_currently_playing' +export { spotifyGetDevicesTool } from './get_devices' +// Episodes +export { spotifyGetEpisodeTool } from './get_episode' +export { spotifyGetEpisodesTool } from './get_episodes' +export { spotifyGetFollowedArtistsTool } from './get_followed_artists' +export { spotifyGetMarketsTool } from './get_markets' +// Browse +export { spotifyGetNewReleasesTool } from './get_new_releases' +// Player Controls +export { spotifyGetPlaybackStateTool } from './get_playback_state' +// Playlists +export { spotifyGetPlaylistTool } from './get_playlist' +export { spotifyGetPlaylistCoverTool } from './get_playlist_cover' +export { spotifyGetPlaylistTracksTool } from './get_playlist_tracks' +export { spotifyGetQueueTool } from './get_queue' +export { spotifyGetRecentlyPlayedTool } from './get_recently_played' +export { spotifyGetSavedAlbumsTool } from './get_saved_albums' +export { spotifyGetSavedAudiobooksTool } from './get_saved_audiobooks' +export { spotifyGetSavedEpisodesTool } from './get_saved_episodes' +export { spotifyGetSavedShowsTool } from './get_saved_shows' +export { spotifyGetSavedTracksTool } from './get_saved_tracks' +// Shows (Podcasts) +export { spotifyGetShowTool } from './get_show' +export { spotifyGetShowEpisodesTool } from './get_show_episodes' +export { spotifyGetShowsTool } from './get_shows' +export { spotifyGetTopArtistsTool } from './get_top_artists' +export { spotifyGetTopTracksTool } from './get_top_tracks' +// Tracks +export { spotifyGetTrackTool } from './get_track' +export { spotifyGetTracksTool } from './get_tracks' +export { spotifyGetUserPlaylistsTool } from './get_user_playlists' +export { spotifyGetUserProfileTool } from './get_user_profile' +export { spotifyPauseTool } from './pause' +export { spotifyPlayTool } from './play' +// Library Management +export { spotifyRemoveSavedAlbumsTool } from './remove_saved_albums' +export { spotifyRemoveSavedAudiobooksTool } from './remove_saved_audiobooks' +export { spotifyRemoveSavedEpisodesTool } from './remove_saved_episodes' +export { spotifyRemoveSavedShowsTool } from './remove_saved_shows' +export { spotifyRemoveSavedTracksTool } from './remove_saved_tracks' +export { spotifyRemoveTracksFromPlaylistTool } from './remove_tracks_from_playlist' +export { spotifyReorderPlaylistItemsTool } from './reorder_playlist_items' +export { spotifyReplacePlaylistItemsTool } from './replace_playlist_items' +export { spotifySaveAlbumsTool } from './save_albums' +export { spotifySaveAudiobooksTool } from './save_audiobooks' +export { spotifySaveEpisodesTool } from './save_episodes' +export { spotifySaveShowsTool } from './save_shows' +export { spotifySaveTracksTool } from './save_tracks' +export { spotifySearchTool } from './search' +export { spotifySeekTool } from './seek' +export { spotifySetRepeatTool } from './set_repeat' +export { spotifySetShuffleTool } from './set_shuffle' +export { spotifySetVolumeTool } from './set_volume' +export { spotifySkipNextTool } from './skip_next' +export { spotifySkipPreviousTool } from './skip_previous' +export { spotifyTransferPlaybackTool } from './transfer_playback' +export { spotifyUnfollowArtistsTool } from './unfollow_artists' +export { spotifyUnfollowPlaylistTool } from './unfollow_playlist' +export { spotifyUpdatePlaylistTool } from './update_playlist' diff --git a/apps/sim/tools/spotify/pause.ts b/apps/sim/tools/spotify/pause.ts new file mode 100644 index 0000000000..7bac7d5bb3 --- /dev/null +++ b/apps/sim/tools/spotify/pause.ts @@ -0,0 +1,52 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyPauseParams, SpotifyPauseResponse } from './types' + +export const spotifyPauseTool: ToolConfig = { + id: 'spotify_pause', + name: 'Spotify Pause', + description: 'Pause playback on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID to pause. If not provided, pauses active device.', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player/pause' + if (params.device_id) { + url += `?device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether playback was paused' }, + }, +} diff --git a/apps/sim/tools/spotify/play.ts b/apps/sim/tools/spotify/play.ts new file mode 100644 index 0000000000..1b304be6a2 --- /dev/null +++ b/apps/sim/tools/spotify/play.ts @@ -0,0 +1,94 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifyPlayParams, SpotifyPlayResponse } from './types' + +export const spotifyPlayTool: ToolConfig = { + id: 'spotify_play', + name: 'Spotify Play', + description: + 'Start or resume playback on Spotify. Can play specific tracks, albums, or playlists.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID to play on. If not provided, plays on active device.', + }, + context_uri: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Spotify URI of album, artist, or playlist to play (e.g., "spotify:album:xxx")', + }, + uris: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Comma-separated track URIs to play (e.g., "spotify:track:xxx,spotify:track:yyy")', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Position in context to start playing (0-based index)', + }, + position_ms: { + type: 'number', + required: false, + visibility: 'user-only', + description: 'Position in track to start from (in milliseconds)', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player/play' + if (params.device_id) { + url += `?device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: any = {} + if (params.context_uri) { + body.context_uri = params.context_uri + } + if (params.uris) { + body.uris = params.uris.split(',').map((uri) => uri.trim()) + } + if (params.offset !== undefined) { + body.offset = { position: params.offset } + } + if (params.position_ms !== undefined) { + body.position_ms = params.position_ms + } + return Object.keys(body).length > 0 ? body : undefined + }, + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether playback started successfully' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_saved_albums.ts b/apps/sim/tools/spotify/remove_saved_albums.ts new file mode 100644 index 0000000000..fe5274dec5 --- /dev/null +++ b/apps/sim/tools/spotify/remove_saved_albums.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyRemoveSavedAlbumsParams { + accessToken: string + albumIds: string +} + +interface SpotifyRemoveSavedAlbumsResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyRemoveSavedAlbumsTool: ToolConfig< + SpotifyRemoveSavedAlbumsParams, + SpotifyRemoveSavedAlbumsResponse +> = { + id: 'spotify_remove_saved_albums', + name: 'Spotify Remove Saved Albums', + description: "Remove albums from the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + albumIds: { + type: 'string', + required: true, + description: 'Comma-separated album IDs (max 20)', + }, + }, + + request: { + url: () => 'https://api.spotify.com/v1/me/albums', + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + ids: params.albumIds + .split(',') + .map((id) => id.trim()) + .slice(0, 20), + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether albums were removed' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_saved_audiobooks.ts b/apps/sim/tools/spotify/remove_saved_audiobooks.ts new file mode 100644 index 0000000000..58518e548c --- /dev/null +++ b/apps/sim/tools/spotify/remove_saved_audiobooks.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyRemoveSavedAudiobooksParams { + accessToken: string + audiobookIds: string +} + +interface SpotifyRemoveSavedAudiobooksResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyRemoveSavedAudiobooksTool: ToolConfig< + SpotifyRemoveSavedAudiobooksParams, + SpotifyRemoveSavedAudiobooksResponse +> = { + id: 'spotify_remove_saved_audiobooks', + name: 'Spotify Remove Saved Audiobooks', + description: "Remove audiobooks from the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + audiobookIds: { + type: 'string', + required: true, + description: 'Comma-separated audiobook IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.audiobookIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/audiobooks?ids=${ids}` + }, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether audiobooks were removed' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_saved_episodes.ts b/apps/sim/tools/spotify/remove_saved_episodes.ts new file mode 100644 index 0000000000..62af650827 --- /dev/null +++ b/apps/sim/tools/spotify/remove_saved_episodes.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyRemoveSavedEpisodesParams { + accessToken: string + episodeIds: string +} + +interface SpotifyRemoveSavedEpisodesResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyRemoveSavedEpisodesTool: ToolConfig< + SpotifyRemoveSavedEpisodesParams, + SpotifyRemoveSavedEpisodesResponse +> = { + id: 'spotify_remove_saved_episodes', + name: 'Spotify Remove Saved Episodes', + description: "Remove podcast episodes from the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + episodeIds: { + type: 'string', + required: true, + description: 'Comma-separated episode IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.episodeIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/episodes?ids=${ids}` + }, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether episodes were removed' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_saved_shows.ts b/apps/sim/tools/spotify/remove_saved_shows.ts new file mode 100644 index 0000000000..f12da679b9 --- /dev/null +++ b/apps/sim/tools/spotify/remove_saved_shows.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyRemoveSavedShowsParams { + accessToken: string + showIds: string +} + +interface SpotifyRemoveSavedShowsResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyRemoveSavedShowsTool: ToolConfig< + SpotifyRemoveSavedShowsParams, + SpotifyRemoveSavedShowsResponse +> = { + id: 'spotify_remove_saved_shows', + name: 'Spotify Remove Saved Shows', + description: "Remove podcast shows from the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + showIds: { + type: 'string', + required: true, + description: 'Comma-separated show IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.showIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/shows?ids=${ids}` + }, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether shows were removed' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_saved_tracks.ts b/apps/sim/tools/spotify/remove_saved_tracks.ts new file mode 100644 index 0000000000..0dac9aa87f --- /dev/null +++ b/apps/sim/tools/spotify/remove_saved_tracks.ts @@ -0,0 +1,63 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyRemoveSavedTracksParams { + accessToken: string + trackIds: string +} + +interface SpotifyRemoveSavedTracksResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifyRemoveSavedTracksTool: ToolConfig< + SpotifyRemoveSavedTracksParams, + SpotifyRemoveSavedTracksResponse +> = { + id: 'spotify_remove_saved_tracks', + name: 'Spotify Remove Saved Tracks', + description: "Remove tracks from the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + trackIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated track IDs to remove (max 50)', + }, + }, + + request: { + url: () => 'https://api.spotify.com/v1/me/tracks', + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + ids: params.trackIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50), + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether tracks were removed successfully' }, + }, +} diff --git a/apps/sim/tools/spotify/remove_tracks_from_playlist.ts b/apps/sim/tools/spotify/remove_tracks_from_playlist.ts new file mode 100644 index 0000000000..222413f59a --- /dev/null +++ b/apps/sim/tools/spotify/remove_tracks_from_playlist.ts @@ -0,0 +1,65 @@ +import type { ToolConfig } from '@/tools/types' +import type { + SpotifyRemoveTracksFromPlaylistParams, + SpotifyRemoveTracksFromPlaylistResponse, +} from './types' + +export const spotifyRemoveTracksFromPlaylistTool: ToolConfig< + SpotifyRemoveTracksFromPlaylistParams, + SpotifyRemoveTracksFromPlaylistResponse +> = { + id: 'spotify_remove_tracks_from_playlist', + name: 'Spotify Remove Tracks from Playlist', + description: 'Remove one or more tracks from a Spotify playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Spotify ID of the playlist', + }, + uris: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Comma-separated Spotify URIs to remove (e.g., "spotify:track:xxx,spotify:track:yyy")', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/tracks`, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const uris = params.uris.split(',').map((uri) => ({ uri: uri.trim() })) + return { tracks: uris } + }, + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + return { + success: true, + output: { + snapshot_id: data.snapshot_id, + }, + } + }, + + outputs: { + snapshot_id: { type: 'string', description: 'New playlist snapshot ID after modification' }, + }, +} diff --git a/apps/sim/tools/spotify/reorder_playlist_items.ts b/apps/sim/tools/spotify/reorder_playlist_items.ts new file mode 100644 index 0000000000..f0287088ac --- /dev/null +++ b/apps/sim/tools/spotify/reorder_playlist_items.ts @@ -0,0 +1,91 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyReorderPlaylistItemsParams { + accessToken: string + playlistId: string + range_start: number + insert_before: number + range_length?: number + snapshot_id?: string +} + +interface SpotifyReorderPlaylistItemsResponse extends ToolResponse { + output: { + snapshot_id: string + } +} + +export const spotifyReorderPlaylistItemsTool: ToolConfig< + SpotifyReorderPlaylistItemsParams, + SpotifyReorderPlaylistItemsResponse +> = { + id: 'spotify_reorder_playlist_items', + name: 'Spotify Reorder Playlist Items', + description: 'Move tracks to a different position in a playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + range_start: { + type: 'number', + required: true, + description: 'Start index of items to reorder', + }, + insert_before: { + type: 'number', + required: true, + description: 'Index to insert items before', + }, + range_length: { + type: 'number', + required: false, + default: 1, + description: 'Number of items to reorder', + }, + snapshot_id: { + type: 'string', + required: false, + description: 'Playlist snapshot ID for concurrency control', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/tracks`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = { + range_start: params.range_start, + insert_before: params.insert_before, + range_length: params.range_length || 1, + } + if (params.snapshot_id) body.snapshot_id = params.snapshot_id + return body + }, + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { snapshot_id: data.snapshot_id || '' }, + } + }, + + outputs: { + snapshot_id: { type: 'string', description: 'New playlist snapshot ID' }, + }, +} diff --git a/apps/sim/tools/spotify/replace_playlist_items.ts b/apps/sim/tools/spotify/replace_playlist_items.ts new file mode 100644 index 0000000000..0bd278e24d --- /dev/null +++ b/apps/sim/tools/spotify/replace_playlist_items.ts @@ -0,0 +1,69 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyReplacePlaylistItemsParams { + accessToken: string + playlistId: string + uris: string +} + +interface SpotifyReplacePlaylistItemsResponse extends ToolResponse { + output: { + snapshot_id: string + } +} + +export const spotifyReplacePlaylistItemsTool: ToolConfig< + SpotifyReplacePlaylistItemsParams, + SpotifyReplacePlaylistItemsResponse +> = { + id: 'spotify_replace_playlist_items', + name: 'Spotify Replace Playlist Items', + description: 'Replace all items in a playlist with new tracks.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + uris: { + type: 'string', + required: true, + description: 'Comma-separated Spotify URIs (max 100)', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/tracks`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + uris: params.uris + .split(',') + .map((uri) => uri.trim()) + .slice(0, 100), + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + return { + success: true, + output: { snapshot_id: data.snapshot_id || '' }, + } + }, + + outputs: { + snapshot_id: { type: 'string', description: 'New playlist snapshot ID' }, + }, +} diff --git a/apps/sim/tools/spotify/save_albums.ts b/apps/sim/tools/spotify/save_albums.ts new file mode 100644 index 0000000000..414967a363 --- /dev/null +++ b/apps/sim/tools/spotify/save_albums.ts @@ -0,0 +1,55 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySaveAlbumsParams { + accessToken: string + albumIds: string +} + +interface SpotifySaveAlbumsResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifySaveAlbumsTool: ToolConfig = + { + id: 'spotify_save_albums', + name: 'Spotify Save Albums', + description: "Save albums to the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + albumIds: { + type: 'string', + required: true, + description: 'Comma-separated album IDs (max 20)', + }, + }, + + request: { + url: () => 'https://api.spotify.com/v1/me/albums', + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + ids: params.albumIds + .split(',') + .map((id) => id.trim()) + .slice(0, 20), + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether albums were saved' }, + }, + } diff --git a/apps/sim/tools/spotify/save_audiobooks.ts b/apps/sim/tools/spotify/save_audiobooks.ts new file mode 100644 index 0000000000..e9d028e5ef --- /dev/null +++ b/apps/sim/tools/spotify/save_audiobooks.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySaveAudiobooksParams { + accessToken: string + audiobookIds: string +} + +interface SpotifySaveAudiobooksResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifySaveAudiobooksTool: ToolConfig< + SpotifySaveAudiobooksParams, + SpotifySaveAudiobooksResponse +> = { + id: 'spotify_save_audiobooks', + name: 'Spotify Save Audiobooks', + description: "Save audiobooks to the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + audiobookIds: { + type: 'string', + required: true, + description: 'Comma-separated audiobook IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.audiobookIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/audiobooks?ids=${ids}` + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether audiobooks were saved' }, + }, +} diff --git a/apps/sim/tools/spotify/save_episodes.ts b/apps/sim/tools/spotify/save_episodes.ts new file mode 100644 index 0000000000..4669bd3087 --- /dev/null +++ b/apps/sim/tools/spotify/save_episodes.ts @@ -0,0 +1,57 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySaveEpisodesParams { + accessToken: string + episodeIds: string +} + +interface SpotifySaveEpisodesResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifySaveEpisodesTool: ToolConfig< + SpotifySaveEpisodesParams, + SpotifySaveEpisodesResponse +> = { + id: 'spotify_save_episodes', + name: 'Spotify Save Episodes', + description: "Save podcast episodes to the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + episodeIds: { + type: 'string', + required: true, + description: 'Comma-separated episode IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.episodeIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/episodes?ids=${ids}` + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether episodes were saved' }, + }, +} diff --git a/apps/sim/tools/spotify/save_shows.ts b/apps/sim/tools/spotify/save_shows.ts new file mode 100644 index 0000000000..a6c2b196a0 --- /dev/null +++ b/apps/sim/tools/spotify/save_shows.ts @@ -0,0 +1,54 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySaveShowsParams { + accessToken: string + showIds: string +} + +interface SpotifySaveShowsResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifySaveShowsTool: ToolConfig = { + id: 'spotify_save_shows', + name: 'Spotify Save Shows', + description: "Save podcast shows to the user's library.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + showIds: { + type: 'string', + required: true, + description: 'Comma-separated show IDs (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.showIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/shows?ids=${ids}` + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether shows were saved' }, + }, +} diff --git a/apps/sim/tools/spotify/save_tracks.ts b/apps/sim/tools/spotify/save_tracks.ts new file mode 100644 index 0000000000..f639720d2c --- /dev/null +++ b/apps/sim/tools/spotify/save_tracks.ts @@ -0,0 +1,48 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifySaveTracksParams, SpotifySaveTracksResponse } from './types' + +export const spotifySaveTracksTool: ToolConfig = + { + id: 'spotify_save_tracks', + name: 'Spotify Save Tracks', + description: "Save tracks to the current user's library (like tracks).", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-library-modify'], + }, + + params: { + trackIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated Spotify track IDs to save (max 50)', + }, + }, + + request: { + url: (params) => + `https://api.spotify.com/v1/me/tracks?ids=${encodeURIComponent(params.trackIds)}`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether the tracks were saved successfully' }, + }, + } diff --git a/apps/sim/tools/spotify/search.ts b/apps/sim/tools/spotify/search.ts new file mode 100644 index 0000000000..0289060422 --- /dev/null +++ b/apps/sim/tools/spotify/search.ts @@ -0,0 +1,157 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifySearchParams, SpotifySearchResponse } from './types' + +export const spotifySearchTool: ToolConfig = { + id: 'spotify_search', + name: 'Spotify Search', + description: + 'Search for tracks, albums, artists, or playlists on Spotify. Returns matching results based on the query.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + }, + + params: { + query: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Search query (e.g., "Bohemian Rhapsody", "artist:Queen", "genre:rock")', + }, + type: { + type: 'string', + required: false, + visibility: 'user-or-llm', + default: 'track', + description: + 'Type of results: track, album, artist, playlist, or comma-separated (e.g., "track,artist")', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-only', + default: 20, + description: 'Maximum number of results to return (1-50)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-only', + default: 0, + description: 'Index of the first result to return for pagination', + }, + market: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'ISO 3166-1 alpha-2 country code to filter results (e.g., "US", "GB")', + }, + }, + + request: { + url: (params) => { + const type = params.type || 'track' + const limit = Math.min(Math.max(params.limit || 20, 1), 50) + const offset = params.offset || 0 + let url = `https://api.spotify.com/v1/search?q=${encodeURIComponent(params.query)}&type=${encodeURIComponent(type)}&limit=${limit}&offset=${offset}` + if (params.market) { + url += `&market=${params.market}` + } + return url + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + const tracks = (data.tracks?.items || []).map((track: any) => ({ + id: track.id, + name: track.name, + artists: track.artists?.map((a: any) => a.name) || [], + album: track.album?.name || '', + duration_ms: track.duration_ms, + popularity: track.popularity, + preview_url: track.preview_url, + external_url: track.external_urls?.spotify || '', + })) + + const artists = (data.artists?.items || []).map((artist: any) => ({ + id: artist.id, + name: artist.name, + genres: artist.genres || [], + popularity: artist.popularity, + followers: artist.followers?.total || 0, + image_url: artist.images?.[0]?.url || null, + external_url: artist.external_urls?.spotify || '', + })) + + const albums = (data.albums?.items || []).map((album: any) => ({ + id: album.id, + name: album.name, + artists: album.artists?.map((a: any) => a.name) || [], + total_tracks: album.total_tracks, + release_date: album.release_date, + image_url: album.images?.[0]?.url || null, + external_url: album.external_urls?.spotify || '', + })) + + const playlists = (data.playlists?.items || []).map((playlist: any) => ({ + id: playlist.id, + name: playlist.name, + description: playlist.description, + owner: playlist.owner?.display_name || '', + total_tracks: playlist.tracks?.total || 0, + image_url: playlist.images?.[0]?.url || null, + external_url: playlist.external_urls?.spotify || '', + })) + + return { + success: true, + output: { + tracks, + artists, + albums, + playlists, + }, + } + }, + + outputs: { + tracks: { + type: 'array', + description: 'List of matching tracks', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Spotify track ID' }, + name: { type: 'string', description: 'Track name' }, + artists: { type: 'array', description: 'List of artist names' }, + album: { type: 'string', description: 'Album name' }, + duration_ms: { type: 'number', description: 'Track duration in milliseconds' }, + popularity: { type: 'number', description: 'Popularity score (0-100)' }, + preview_url: { type: 'string', description: 'URL to 30-second preview' }, + external_url: { type: 'string', description: 'Spotify URL' }, + }, + }, + }, + artists: { + type: 'array', + description: 'List of matching artists', + }, + albums: { + type: 'array', + description: 'List of matching albums', + }, + playlists: { + type: 'array', + description: 'List of matching playlists', + }, + }, +} diff --git a/apps/sim/tools/spotify/seek.ts b/apps/sim/tools/spotify/seek.ts new file mode 100644 index 0000000000..049525a2ab --- /dev/null +++ b/apps/sim/tools/spotify/seek.ts @@ -0,0 +1,67 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySeekParams { + accessToken: string + position_ms: number + device_id?: string +} + +interface SpotifySeekResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifySeekTool: ToolConfig = { + id: 'spotify_seek', + name: 'Spotify Seek', + description: 'Seek to a position in the currently playing track.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + position_ms: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Position in milliseconds to seek to', + }, + device_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Device ID to target', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/me/player/seek?position_ms=${params.position_ms}` + if (params.device_id) { + url += `&device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether seek was successful' }, + }, +} diff --git a/apps/sim/tools/spotify/set_repeat.ts b/apps/sim/tools/spotify/set_repeat.ts new file mode 100644 index 0000000000..02e85fa508 --- /dev/null +++ b/apps/sim/tools/spotify/set_repeat.ts @@ -0,0 +1,67 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySetRepeatParams { + accessToken: string + state: string + device_id?: string +} + +interface SpotifySetRepeatResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifySetRepeatTool: ToolConfig = { + id: 'spotify_set_repeat', + name: 'Spotify Set Repeat', + description: 'Set the repeat mode for playback.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + state: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Repeat mode: "off", "track", or "context"', + }, + device_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Device ID to target', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/me/player/repeat?state=${params.state}` + if (params.device_id) { + url += `&device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether repeat mode was set successfully' }, + }, +} diff --git a/apps/sim/tools/spotify/set_shuffle.ts b/apps/sim/tools/spotify/set_shuffle.ts new file mode 100644 index 0000000000..e84c3c6457 --- /dev/null +++ b/apps/sim/tools/spotify/set_shuffle.ts @@ -0,0 +1,68 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifySetShuffleParams { + accessToken: string + state: boolean + device_id?: string +} + +interface SpotifySetShuffleResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifySetShuffleTool: ToolConfig = + { + id: 'spotify_set_shuffle', + name: 'Spotify Set Shuffle', + description: 'Turn shuffle on or off.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + state: { + type: 'boolean', + required: true, + visibility: 'user-or-llm', + description: 'true for shuffle on, false for off', + }, + device_id: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Device ID to target', + }, + }, + + request: { + url: (params) => { + let url = `https://api.spotify.com/v1/me/player/shuffle?state=${params.state}` + if (params.device_id) { + url += `&device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether shuffle was set successfully' }, + }, + } diff --git a/apps/sim/tools/spotify/set_volume.ts b/apps/sim/tools/spotify/set_volume.ts new file mode 100644 index 0000000000..045426e5f8 --- /dev/null +++ b/apps/sim/tools/spotify/set_volume.ts @@ -0,0 +1,59 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifySetVolumeParams, SpotifySetVolumeResponse } from './types' + +export const spotifySetVolumeTool: ToolConfig = { + id: 'spotify_set_volume', + name: 'Spotify Set Volume', + description: 'Set the playback volume on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + volume_percent: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Volume level (0 to 100)', + }, + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID. If not provided, uses active device.', + }, + }, + + request: { + url: (params) => { + const volume = Math.min(Math.max(params.volume_percent, 0), 100) + let url = `https://api.spotify.com/v1/me/player/volume?volume_percent=${volume}` + if (params.device_id) { + url += `&device_id=${params.device_id}` + } + return url + }, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether volume was set' }, + }, +} diff --git a/apps/sim/tools/spotify/skip_next.ts b/apps/sim/tools/spotify/skip_next.ts new file mode 100644 index 0000000000..21e4a7d3a0 --- /dev/null +++ b/apps/sim/tools/spotify/skip_next.ts @@ -0,0 +1,52 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifySkipNextParams, SpotifySkipNextResponse } from './types' + +export const spotifySkipNextTool: ToolConfig = { + id: 'spotify_skip_next', + name: 'Spotify Skip to Next', + description: 'Skip to the next track on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID. If not provided, uses active device.', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player/next' + if (params.device_id) { + url += `?device_id=${params.device_id}` + } + return url + }, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether skip was successful' }, + }, +} diff --git a/apps/sim/tools/spotify/skip_previous.ts b/apps/sim/tools/spotify/skip_previous.ts new file mode 100644 index 0000000000..4246765016 --- /dev/null +++ b/apps/sim/tools/spotify/skip_previous.ts @@ -0,0 +1,55 @@ +import type { ToolConfig } from '@/tools/types' +import type { SpotifySkipPreviousParams, SpotifySkipPreviousResponse } from './types' + +export const spotifySkipPreviousTool: ToolConfig< + SpotifySkipPreviousParams, + SpotifySkipPreviousResponse +> = { + id: 'spotify_skip_previous', + name: 'Spotify Skip to Previous', + description: 'Skip to the previous track on Spotify.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + device_id: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID. If not provided, uses active device.', + }, + }, + + request: { + url: (params) => { + let url = 'https://api.spotify.com/v1/me/player/previous' + if (params.device_id) { + url += `?device_id=${params.device_id}` + } + return url + }, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { + success: true, + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether skip was successful' }, + }, +} diff --git a/apps/sim/tools/spotify/transfer_playback.ts b/apps/sim/tools/spotify/transfer_playback.ts new file mode 100644 index 0000000000..0f89da96dc --- /dev/null +++ b/apps/sim/tools/spotify/transfer_playback.ts @@ -0,0 +1,69 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyTransferPlaybackParams { + accessToken: string + device_id: string + play?: boolean +} + +interface SpotifyTransferPlaybackResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifyTransferPlaybackTool: ToolConfig< + SpotifyTransferPlaybackParams, + SpotifyTransferPlaybackResponse +> = { + id: 'spotify_transfer_playback', + name: 'Spotify Transfer Playback', + description: 'Transfer playback to a different device.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-modify-playback-state'], + }, + + params: { + device_id: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Device ID to transfer playback to', + }, + play: { + type: 'boolean', + required: false, + visibility: 'user-only', + default: true, + description: 'Whether to start playing on the new device', + }, + }, + + request: { + url: () => 'https://api.spotify.com/v1/me/player', + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + device_ids: [params.device_id], + play: params.play ?? true, + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether transfer was successful' }, + }, +} diff --git a/apps/sim/tools/spotify/types.ts b/apps/sim/tools/spotify/types.ts new file mode 100644 index 0000000000..a8844ee095 --- /dev/null +++ b/apps/sim/tools/spotify/types.ts @@ -0,0 +1,1031 @@ +import type { ToolResponse } from '@/tools/types' + +/** + * Base params that include OAuth access token + */ +export interface SpotifyBaseParams { + accessToken: string +} + +/** + * Common Spotify objects + */ +export interface SpotifyImage { + url: string + height: number | null + width: number | null +} + +export interface SpotifyExternalUrls { + spotify: string +} + +export interface SpotifyArtistSimplified { + id: string + name: string + external_urls: SpotifyExternalUrls +} + +export interface SpotifyAlbumSimplified { + id: string + name: string + album_type: string + total_tracks: number + release_date: string + images: SpotifyImage[] + artists: SpotifyArtistSimplified[] + external_urls: SpotifyExternalUrls +} + +export interface SpotifyTrack { + id: string + name: string + duration_ms: number + explicit: boolean + popularity: number + preview_url: string | null + track_number: number + disc_number: number + album: SpotifyAlbumSimplified + artists: SpotifyArtistSimplified[] + external_urls: SpotifyExternalUrls + uri: string +} + +export interface SpotifyArtist { + id: string + name: string + genres: string[] + popularity: number + followers: { total: number } + images: SpotifyImage[] + external_urls: SpotifyExternalUrls +} + +export interface SpotifyAlbum { + id: string + name: string + album_type: string + total_tracks: number + release_date: string + release_date_precision: string + label: string + popularity: number + genres: string[] + images: SpotifyImage[] + artists: SpotifyArtistSimplified[] + tracks: { + items: SpotifyTrack[] + total: number + } + external_urls: SpotifyExternalUrls +} + +export interface SpotifyPlaylist { + id: string + name: string + description: string | null + public: boolean + collaborative: boolean + owner: { + id: string + display_name: string + } + images: SpotifyImage[] + tracks: { + total: number + } + external_urls: SpotifyExternalUrls + snapshot_id: string +} + +export interface SpotifyPlaylistTrack { + added_at: string + added_by: { + id: string + } + track: SpotifyTrack +} + +export interface SpotifyUser { + id: string + display_name: string + email?: string + country?: string + product?: string + followers: { total: number } + images: SpotifyImage[] + external_urls: SpotifyExternalUrls +} + +export interface SpotifyDevice { + id: string + is_active: boolean + is_private_session: boolean + is_restricted: boolean + name: string + type: string + volume_percent: number +} + +export interface SpotifyPlaybackState { + device: SpotifyDevice + shuffle_state: boolean + repeat_state: string + timestamp: number + progress_ms: number + is_playing: boolean + item: SpotifyTrack | null + currently_playing_type: string +} + +/** + * Search + */ +export interface SpotifySearchParams extends SpotifyBaseParams { + query: string + type?: string + limit?: number + offset?: number + market?: string +} + +export interface SpotifySearchResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + artists: string[] + album: string + duration_ms: number + popularity: number + preview_url: string | null + external_url: string + }> + artists: Array<{ + id: string + name: string + genres: string[] + popularity: number + followers: number + image_url: string | null + external_url: string + }> + albums: Array<{ + id: string + name: string + artists: string[] + total_tracks: number + release_date: string + image_url: string | null + external_url: string + }> + playlists: Array<{ + id: string + name: string + description: string | null + owner: string + total_tracks: number + image_url: string | null + external_url: string + }> + } +} + +/** + * Get Track + */ +export interface SpotifyGetTrackParams extends SpotifyBaseParams { + trackId: string + market?: string +} + +export interface SpotifyGetTrackResponse extends ToolResponse { + output: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + explicit: boolean + popularity: number + preview_url: string | null + external_url: string + uri: string + } +} + +/** + * Get Multiple Tracks + */ +export interface SpotifyGetTracksParams extends SpotifyBaseParams { + trackIds: string + market?: string +} + +export interface SpotifyGetTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + explicit: boolean + popularity: number + preview_url: string | null + external_url: string + }> + } +} + +/** + * Get Album + */ +export interface SpotifyGetAlbumParams extends SpotifyBaseParams { + albumId: string + market?: string +} + +export interface SpotifyGetAlbumResponse extends ToolResponse { + output: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album_type: string + total_tracks: number + release_date: string + label: string + popularity: number + genres: string[] + image_url: string | null + tracks: Array<{ + id: string + name: string + duration_ms: number + track_number: number + }> + external_url: string + } +} + +/** + * Get Album Tracks + */ +export interface SpotifyGetAlbumTracksParams extends SpotifyBaseParams { + albumId: string + limit?: number + offset?: number + market?: string +} + +export interface SpotifyGetAlbumTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + duration_ms: number + track_number: number + disc_number: number + explicit: boolean + preview_url: string | null + }> + total: number + next: string | null + } +} + +/** + * Get Artist + */ +export interface SpotifyGetArtistParams extends SpotifyBaseParams { + artistId: string +} + +export interface SpotifyGetArtistResponse extends ToolResponse { + output: { + id: string + name: string + genres: string[] + popularity: number + followers: number + image_url: string | null + external_url: string + } +} + +/** + * Get Artist Albums + */ +export interface SpotifyGetArtistAlbumsParams extends SpotifyBaseParams { + artistId: string + include_groups?: string + limit?: number + offset?: number + market?: string +} + +export interface SpotifyGetArtistAlbumsResponse extends ToolResponse { + output: { + albums: Array<{ + id: string + name: string + album_type: string + total_tracks: number + release_date: string + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +/** + * Get Artist Top Tracks + */ +export interface SpotifyGetArtistTopTracksParams extends SpotifyBaseParams { + artistId: string + market?: string +} + +export interface SpotifyGetArtistTopTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + popularity: number + preview_url: string | null + external_url: string + }> + } +} + +/** + * Get Playlist + */ +export interface SpotifyGetPlaylistParams extends SpotifyBaseParams { + playlistId: string + market?: string +} + +export interface SpotifyGetPlaylistResponse extends ToolResponse { + output: { + id: string + name: string + description: string | null + public: boolean + collaborative: boolean + owner: { + id: string + display_name: string + } + image_url: string | null + total_tracks: number + snapshot_id: string + external_url: string + } +} + +/** + * Get Playlist Tracks + */ +export interface SpotifyGetPlaylistTracksParams extends SpotifyBaseParams { + playlistId: string + limit?: number + offset?: number + market?: string +} + +export interface SpotifyGetPlaylistTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + added_at: string + added_by: string + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + popularity: number + external_url: string + } + }> + total: number + next: string | null + } +} + +/** + * Get User Playlists + */ +export interface SpotifyGetUserPlaylistsParams extends SpotifyBaseParams { + limit?: number + offset?: number +} + +export interface SpotifyGetUserPlaylistsResponse extends ToolResponse { + output: { + playlists: Array<{ + id: string + name: string + description: string | null + public: boolean + collaborative: boolean + owner: string + total_tracks: number + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +/** + * Create Playlist + */ +export interface SpotifyCreatePlaylistParams extends SpotifyBaseParams { + name: string + description?: string + public?: boolean + collaborative?: boolean +} + +export interface SpotifyCreatePlaylistResponse extends ToolResponse { + output: { + id: string + name: string + description: string | null + public: boolean + collaborative: boolean + snapshot_id: string + external_url: string + } +} + +/** + * Add Tracks to Playlist + */ +export interface SpotifyAddTracksToPlaylistParams extends SpotifyBaseParams { + playlistId: string + uris: string + position?: number +} + +export interface SpotifyAddTracksToPlaylistResponse extends ToolResponse { + output: { + snapshot_id: string + } +} + +/** + * Remove Tracks from Playlist + */ +export interface SpotifyRemoveTracksFromPlaylistParams extends SpotifyBaseParams { + playlistId: string + uris: string +} + +export interface SpotifyRemoveTracksFromPlaylistResponse extends ToolResponse { + output: { + snapshot_id: string + } +} + +/** + * Update Playlist + */ +export interface SpotifyUpdatePlaylistParams extends SpotifyBaseParams { + playlistId: string + name?: string + description?: string + public?: boolean + collaborative?: boolean +} + +export interface SpotifyUpdatePlaylistResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Get Current User + */ +export interface SpotifyGetCurrentUserParams extends SpotifyBaseParams {} + +export interface SpotifyGetCurrentUserResponse extends ToolResponse { + output: { + id: string + display_name: string + email: string | null + country: string | null + product: string | null + followers: number + image_url: string | null + external_url: string + } +} + +/** + * Get User Profile + */ +export interface SpotifyGetUserProfileParams extends SpotifyBaseParams { + userId: string +} + +export interface SpotifyGetUserProfileResponse extends ToolResponse { + output: { + id: string + display_name: string + followers: number + image_url: string | null + external_url: string + } +} + +/** + * Get Top Items (Tracks or Artists) + */ +export interface SpotifyGetTopItemsParams extends SpotifyBaseParams { + type: 'tracks' | 'artists' + time_range?: 'short_term' | 'medium_term' | 'long_term' + limit?: number + offset?: number +} + +export interface SpotifyGetTopTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + popularity: number + external_url: string + }> + total: number + next: string | null + } +} + +export interface SpotifyGetTopArtistsResponse extends ToolResponse { + output: { + artists: Array<{ + id: string + name: string + genres: string[] + popularity: number + followers: number + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +/** + * Get Recently Played + */ +export interface SpotifyGetRecentlyPlayedParams extends SpotifyBaseParams { + limit?: number + after?: number + before?: number +} + +export interface SpotifyGetRecentlyPlayedResponse extends ToolResponse { + output: { + items: Array<{ + played_at: string + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + external_url: string + } + }> + next: string | null + } +} + +/** + * Get Saved Tracks + */ +export interface SpotifyGetSavedTracksParams extends SpotifyBaseParams { + limit?: number + offset?: number + market?: string +} + +export interface SpotifyGetSavedTracksResponse extends ToolResponse { + output: { + tracks: Array<{ + added_at: string + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + popularity: number + external_url: string + } + }> + total: number + next: string | null + } +} + +/** + * Save Tracks + */ +export interface SpotifySaveTracksParams extends SpotifyBaseParams { + trackIds: string +} + +export interface SpotifySaveTracksResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Remove Saved Tracks + */ +export interface SpotifyRemoveSavedTracksParams extends SpotifyBaseParams { + trackIds: string +} + +export interface SpotifyRemoveSavedTracksResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Check Saved Tracks + */ +export interface SpotifyCheckSavedTracksParams extends SpotifyBaseParams { + trackIds: string +} + +export interface SpotifyCheckSavedTracksResponse extends ToolResponse { + output: { + results: Array<{ + id: string + saved: boolean + }> + all_saved: boolean + none_saved: boolean + } +} + +/** + * Browse Categories + */ +export interface SpotifyBrowseCategoriesParams extends SpotifyBaseParams { + country?: string + locale?: string + limit?: number + offset?: number +} + +export interface SpotifyBrowseCategoriesResponse extends ToolResponse { + output: { + categories: Array<{ + id: string + name: string + icon_url: string | null + }> + total: number + next: string | null + } +} + +/** + * Browse New Releases + */ +export interface SpotifyBrowseNewReleasesParams extends SpotifyBaseParams { + country?: string + limit?: number + offset?: number +} + +export interface SpotifyBrowseNewReleasesResponse extends ToolResponse { + output: { + albums: Array<{ + id: string + name: string + artists: string[] + album_type: string + total_tracks: number + release_date: string + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +/** + * Player - Get Playback State + */ +export interface SpotifyGetPlaybackStateParams extends SpotifyBaseParams { + market?: string +} + +export interface SpotifyGetPlaybackStateResponse extends ToolResponse { + output: { + is_playing: boolean + device: { + id: string + name: string + type: string + volume_percent: number + } | null + progress_ms: number | null + currently_playing_type: string + shuffle_state: boolean + repeat_state: string + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + } | null + } +} + +/** + * Player - Get Currently Playing + */ +export interface SpotifyGetCurrentlyPlayingParams extends SpotifyBaseParams { + market?: string +} + +export interface SpotifyGetCurrentlyPlayingResponse extends ToolResponse { + output: { + is_playing: boolean + progress_ms: number | null + track: { + id: string + name: string + artists: Array<{ id: string; name: string }> + album: { + id: string + name: string + image_url: string | null + } + duration_ms: number + external_url: string + } | null + } +} + +/** + * Player - Get Devices + */ +export interface SpotifyGetDevicesParams extends SpotifyBaseParams {} + +export interface SpotifyGetDevicesResponse extends ToolResponse { + output: { + devices: Array<{ + id: string + is_active: boolean + is_private_session: boolean + is_restricted: boolean + name: string + type: string + volume_percent: number + }> + } +} + +/** + * Player - Play + */ +export interface SpotifyPlayParams extends SpotifyBaseParams { + device_id?: string + context_uri?: string + uris?: string + offset?: number + position_ms?: number +} + +export interface SpotifyPlayResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Pause + */ +export interface SpotifyPauseParams extends SpotifyBaseParams { + device_id?: string +} + +export interface SpotifyPauseResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Skip Next + */ +export interface SpotifySkipNextParams extends SpotifyBaseParams { + device_id?: string +} + +export interface SpotifySkipNextResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Skip Previous + */ +export interface SpotifySkipPreviousParams extends SpotifyBaseParams { + device_id?: string +} + +export interface SpotifySkipPreviousResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Seek + */ +export interface SpotifySeekParams extends SpotifyBaseParams { + position_ms: number + device_id?: string +} + +export interface SpotifySeekResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Set Volume + */ +export interface SpotifySetVolumeParams extends SpotifyBaseParams { + volume_percent: number + device_id?: string +} + +export interface SpotifySetVolumeResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Add to Queue + */ +export interface SpotifyAddToQueueParams extends SpotifyBaseParams { + uri: string + device_id?: string +} + +export interface SpotifyAddToQueueResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Transfer Playback + */ +export interface SpotifyTransferPlaybackParams extends SpotifyBaseParams { + device_id: string + play?: boolean +} + +export interface SpotifyTransferPlaybackResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Set Repeat + */ +export interface SpotifySetRepeatParams extends SpotifyBaseParams { + state: 'track' | 'context' | 'off' + device_id?: string +} + +export interface SpotifySetRepeatResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Player - Set Shuffle + */ +export interface SpotifySetShuffleParams extends SpotifyBaseParams { + state: boolean + device_id?: string +} + +export interface SpotifySetShuffleResponse extends ToolResponse { + output: { + success: boolean + } +} + +/** + * Get New Releases + */ +export interface SpotifyGetNewReleasesParams extends SpotifyBaseParams { + country?: string + limit?: number + offset?: number +} + +export interface SpotifyGetNewReleasesResponse extends ToolResponse { + output: { + albums: Array<{ + id: string + name: string + artists: Array<{ id: string; name: string }> + release_date: string + total_tracks: number + album_type: string + image_url: string | null + external_url: string + }> + total: number + next: string | null + } +} + +/** + * Get Categories + */ +export interface SpotifyGetCategoriesParams extends SpotifyBaseParams { + country?: string + locale?: string + limit?: number +} + +export interface SpotifyGetCategoriesResponse extends ToolResponse { + output: { + categories: Array<{ + id: string + name: string + icon_url: string | null + }> + total: number + } +} diff --git a/apps/sim/tools/spotify/unfollow_artists.ts b/apps/sim/tools/spotify/unfollow_artists.ts new file mode 100644 index 0000000000..300bc04992 --- /dev/null +++ b/apps/sim/tools/spotify/unfollow_artists.ts @@ -0,0 +1,64 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyUnfollowArtistsParams { + accessToken: string + artistIds: string +} + +interface SpotifyUnfollowArtistsResponse extends ToolResponse { + output: { + success: boolean + } +} + +export const spotifyUnfollowArtistsTool: ToolConfig< + SpotifyUnfollowArtistsParams, + SpotifyUnfollowArtistsResponse +> = { + id: 'spotify_unfollow_artists', + name: 'Spotify Unfollow Artists', + description: 'Unfollow one or more artists.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['user-follow-modify'], + }, + + params: { + artistIds: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Comma-separated artist IDs to unfollow (max 50)', + }, + }, + + request: { + url: (params) => { + const ids = params.artistIds + .split(',') + .map((id) => id.trim()) + .slice(0, 50) + .join(',') + return `https://api.spotify.com/v1/me/following?type=artist&ids=${ids}` + }, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (): Promise => { + return { + success: true, + output: { success: true }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether artists were unfollowed successfully' }, + }, +} diff --git a/apps/sim/tools/spotify/unfollow_playlist.ts b/apps/sim/tools/spotify/unfollow_playlist.ts new file mode 100644 index 0000000000..b1d40d017a --- /dev/null +++ b/apps/sim/tools/spotify/unfollow_playlist.ts @@ -0,0 +1,50 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyUnfollowPlaylistParams { + accessToken: string + playlistId: string +} + +interface SpotifyUnfollowPlaylistResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyUnfollowPlaylistTool: ToolConfig< + SpotifyUnfollowPlaylistParams, + SpotifyUnfollowPlaylistResponse +> = { + id: 'spotify_unfollow_playlist', + name: 'Spotify Unfollow Playlist', + description: 'Unfollow (unsave) a playlist.', + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}/followers`, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + }), + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether unfollow succeeded' }, + }, +} diff --git a/apps/sim/tools/spotify/update_playlist.ts b/apps/sim/tools/spotify/update_playlist.ts new file mode 100644 index 0000000000..b654981b4f --- /dev/null +++ b/apps/sim/tools/spotify/update_playlist.ts @@ -0,0 +1,76 @@ +import type { ToolConfig, ToolResponse } from '@/tools/types' + +interface SpotifyUpdatePlaylistParams { + accessToken: string + playlistId: string + name?: string + description?: string + public?: boolean +} + +interface SpotifyUpdatePlaylistResponse extends ToolResponse { + output: { success: boolean } +} + +export const spotifyUpdatePlaylistTool: ToolConfig< + SpotifyUpdatePlaylistParams, + SpotifyUpdatePlaylistResponse +> = { + id: 'spotify_update_playlist', + name: 'Spotify Update Playlist', + description: "Update a playlist's name, description, or visibility.", + version: '1.0.0', + + oauth: { + required: true, + provider: 'spotify', + requiredScopes: ['playlist-modify-public', 'playlist-modify-private'], + }, + + params: { + playlistId: { + type: 'string', + required: true, + description: 'The Spotify playlist ID', + }, + name: { + type: 'string', + required: false, + description: 'New name for the playlist', + }, + description: { + type: 'string', + required: false, + description: 'New description for the playlist', + }, + public: { + type: 'boolean', + required: false, + description: 'Whether the playlist should be public', + }, + }, + + request: { + url: (params) => `https://api.spotify.com/v1/playlists/${params.playlistId}`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = {} + if (params.name !== undefined) body.name = params.name + if (params.description !== undefined) body.description = params.description + if (params.public !== undefined) body.public = params.public + return body + }, + }, + + transformResponse: async (): Promise => { + return { success: true, output: { success: true } } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether update succeeded' }, + }, +} From 821d127c00d6ac80d53c2010206612bb4d5194c7 Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 19:24:47 -0800 Subject: [PATCH 31/34] fix(build): explicitly install shims module from anthropic and openai in stagehand route (#2350) --- apps/sim/app/api/tools/stagehand/agent/route.ts | 7 +++++-- apps/sim/app/api/tools/stagehand/extract/route.ts | 7 +++++-- apps/sim/next.config.ts | 1 - 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/sim/app/api/tools/stagehand/agent/route.ts b/apps/sim/app/api/tools/stagehand/agent/route.ts index 34177f612b..1e5f480fce 100644 --- a/apps/sim/app/api/tools/stagehand/agent/route.ts +++ b/apps/sim/app/api/tools/stagehand/agent/route.ts @@ -1,4 +1,3 @@ -import { Stagehand } from '@browserbasehq/stagehand' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { env } from '@/lib/core/config/env' @@ -7,6 +6,8 @@ import { ensureZodObject, normalizeUrl } from '@/app/api/tools/stagehand/utils' const logger = createLogger('StagehandAgentAPI') +type StagehandType = import('@browserbasehq/stagehand').Stagehand + const BROWSERBASE_API_KEY = env.BROWSERBASE_API_KEY const BROWSERBASE_PROJECT_ID = env.BROWSERBASE_PROJECT_ID @@ -89,7 +90,7 @@ function substituteVariables(text: string, variables: Record | u } export async function POST(request: NextRequest) { - let stagehand: Stagehand | null = null + let stagehand: StagehandType | null = null try { const body = await request.json() @@ -157,6 +158,8 @@ export async function POST(request: NextRequest) { try { logger.info('Initializing Stagehand with Browserbase (v3)', { provider, modelName }) + const { Stagehand } = await import('@browserbasehq/stagehand') + stagehand = new Stagehand({ env: 'BROWSERBASE', apiKey: BROWSERBASE_API_KEY, diff --git a/apps/sim/app/api/tools/stagehand/extract/route.ts b/apps/sim/app/api/tools/stagehand/extract/route.ts index bd8a1e96ab..7da282815d 100644 --- a/apps/sim/app/api/tools/stagehand/extract/route.ts +++ b/apps/sim/app/api/tools/stagehand/extract/route.ts @@ -1,4 +1,3 @@ -import { Stagehand } from '@browserbasehq/stagehand' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { env } from '@/lib/core/config/env' @@ -7,6 +6,8 @@ import { ensureZodObject, normalizeUrl } from '@/app/api/tools/stagehand/utils' const logger = createLogger('StagehandExtractAPI') +type StagehandType = import('@browserbasehq/stagehand').Stagehand + const BROWSERBASE_API_KEY = env.BROWSERBASE_API_KEY const BROWSERBASE_PROJECT_ID = env.BROWSERBASE_PROJECT_ID @@ -21,7 +22,7 @@ const requestSchema = z.object({ }) export async function POST(request: NextRequest) { - let stagehand: Stagehand | null = null + let stagehand: StagehandType | null = null try { const body = await request.json() @@ -93,6 +94,8 @@ export async function POST(request: NextRequest) { logger.info('Initializing Stagehand with Browserbase (v3)', { provider, modelName }) + const { Stagehand } = await import('@browserbasehq/stagehand') + stagehand = new Stagehand({ env: 'BROWSERBASE', apiKey: BROWSERBASE_API_KEY, diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index e2f3ebaba0..20e8063871 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -79,7 +79,6 @@ const nextConfig: NextConfig = { 'pino', 'pino-pretty', 'thread-stream', - '@browserbasehq/stagehand', ], experimental: { optimizeCss: true, From 9e3e18601c9bd2dfef01f654403be12ea0b317a1 Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 20:14:53 -0800 Subject: [PATCH 32/34] fix(next): externalize playwright and ws (#2352) --- apps/sim/next.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index 20e8063871..3e3e22bc89 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -79,7 +79,11 @@ const nextConfig: NextConfig = { 'pino', 'pino-pretty', 'thread-stream', + 'ws', ], + outputFileTracingIncludes: { + '/api/tools/stagehand/*': ['./node_modules/ws/**/*'], + }, experimental: { optimizeCss: true, turbopackSourceMaps: false, From 65ac64c2cf27963faf907da6652a1a65158b4d4d Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 20:15:06 -0800 Subject: [PATCH 33/34] feat(i18n): update translations (#2351) Co-authored-by: waleedlatif1 --- apps/docs/content/docs/de/tools/grafana.mdx | 20 +- apps/docs/content/docs/de/tools/spotify.mdx | 1453 +++++++++++++++++++ apps/docs/content/docs/de/tools/zep.mdx | 11 +- apps/docs/content/docs/es/tools/grafana.mdx | 20 +- apps/docs/content/docs/es/tools/spotify.mdx | 1453 +++++++++++++++++++ apps/docs/content/docs/es/tools/zep.mdx | 11 +- apps/docs/content/docs/fr/tools/grafana.mdx | 34 +- apps/docs/content/docs/fr/tools/spotify.mdx | 1453 +++++++++++++++++++ apps/docs/content/docs/fr/tools/zep.mdx | 15 +- apps/docs/content/docs/ja/tools/grafana.mdx | 18 +- apps/docs/content/docs/ja/tools/spotify.mdx | 1452 ++++++++++++++++++ apps/docs/content/docs/ja/tools/zep.mdx | 11 +- apps/docs/content/docs/zh/tools/grafana.mdx | 38 +- apps/docs/content/docs/zh/tools/spotify.mdx | 1452 ++++++++++++++++++ apps/docs/content/docs/zh/tools/zep.mdx | 11 +- apps/docs/i18n.lock | 490 ++++++- 16 files changed, 7859 insertions(+), 83 deletions(-) create mode 100644 apps/docs/content/docs/de/tools/spotify.mdx create mode 100644 apps/docs/content/docs/es/tools/spotify.mdx create mode 100644 apps/docs/content/docs/fr/tools/spotify.mdx create mode 100644 apps/docs/content/docs/ja/tools/spotify.mdx create mode 100644 apps/docs/content/docs/zh/tools/spotify.mdx diff --git a/apps/docs/content/docs/de/tools/grafana.mdx b/apps/docs/content/docs/de/tools/grafana.mdx index 8e694f5c97..1747ea5c5a 100644 --- a/apps/docs/content/docs/de/tools/grafana.mdx +++ b/apps/docs/content/docs/de/tools/grafana.mdx @@ -321,7 +321,7 @@ Eine Anmerkung auf einem Dashboard oder als globale Anmerkung erstellen | `organizationId` | string | Nein | Organisations-ID für Multi-Org-Grafana-Instanzen | | `text` | string | Ja | Der Textinhalt der Anmerkung | | `tags` | string | Nein | Kommagetrennte Liste von Tags | -| `dashboardUid` | string | Nein | UID des Dashboards, zu dem die Anmerkung hinzugefügt werden soll \(optional für globale Anmerkungen\) | +| `dashboardUid` | string | Ja | UID des Dashboards, zu dem die Anmerkung hinzugefügt werden soll | | `panelId` | number | Nein | ID des Panels, zu dem die Anmerkung hinzugefügt werden soll | | `time` | number | Nein | Startzeit in Epochenmillisekunden \(standardmäßig jetzt\) | | `timeEnd` | number | Nein | Endzeit in Epochenmillisekunden \(für Bereichsanmerkungen\) | @@ -346,11 +346,11 @@ Anmerkungen nach Zeitraum, Dashboard oder Tags abfragen | `organizationId` | string | Nein | Organisations-ID für Multi-Org-Grafana-Instanzen | | `from` | number | Nein | Startzeit in Epochenmillisekunden | | `to` | number | Nein | Endzeit in Epochenmillisekunden | -| `dashboardUid` | string | Nein | Nach Dashboard-UID filtern | +| `dashboardUid` | string | Ja | Dashboard-UID, von der Anmerkungen abgefragt werden sollen | | `panelId` | number | Nein | Nach Panel-ID filtern | -| `tags` | string | Nein | Kommagetrennte Liste von Tags, nach denen gefiltert werden soll | +| `tags` | string | Nein | Kommagetrennte Liste von Tags zum Filtern | | `type` | string | Nein | Nach Typ filtern \(alert oder annotation\) | -| `limit` | number | Nein | Maximale Anzahl von zurückzugebenden Anmerkungen | +| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Anmerkungen | #### Ausgabe @@ -481,12 +481,22 @@ Einen neuen Ordner in Grafana erstellen #### Ausgabe -| Parameter | Typ | Beschreibung | +| Parameter | Type | Beschreibung | | --------- | ---- | ----------- | | `id` | number | Die numerische ID des erstellten Ordners | | `uid` | string | Die UID des erstellten Ordners | | `title` | string | Der Titel des erstellten Ordners | | `url` | string | Der URL-Pfad zum Ordner | +| `hasAcl` | boolean | Ob der Ordner benutzerdefinierte ACL-Berechtigungen hat | +| `canSave` | boolean | Ob der aktuelle Benutzer den Ordner speichern kann | +| `canEdit` | boolean | Ob der aktuelle Benutzer den Ordner bearbeiten kann | +| `canAdmin` | boolean | Ob der aktuelle Benutzer Administratorrechte für den Ordner hat | +| `canDelete` | boolean | Ob der aktuelle Benutzer den Ordner löschen kann | +| `createdBy` | string | Benutzername desjenigen, der den Ordner erstellt hat | +| `created` | string | Zeitstempel, wann der Ordner erstellt wurde | +| `updatedBy` | string | Benutzername desjenigen, der den Ordner zuletzt aktualisiert hat | +| `updated` | string | Zeitstempel, wann der Ordner zuletzt aktualisiert wurde | +| `version` | number | Versionsnummer des Ordners | ## Notizen diff --git a/apps/docs/content/docs/de/tools/spotify.mdx b/apps/docs/content/docs/de/tools/spotify.mdx new file mode 100644 index 0000000000..0be4114350 --- /dev/null +++ b/apps/docs/content/docs/de/tools/spotify.mdx @@ -0,0 +1,1453 @@ +--- +title: Spotify +description: Musik suchen, Playlists verwalten, Wiedergabe steuern und auf deine + Bibliothek zugreifen +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Nutzungsanleitung + +Integriere Spotify in deinen Workflow. Suche nach Titeln, Alben, Künstlern und Playlists. Verwalte Playlists, greife auf deine Bibliothek zu, steuere die Wiedergabe, durchsuche Podcasts und Hörbücher. + +## Tools + +### `spotify_search` + +Suche nach Titeln, Alben, Künstlern oder Playlists auf Spotify. Liefert passende Ergebnisse basierend auf der Anfrage. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `query` | string | Ja | Suchanfrage \(z.B. "Bohemian Rhapsody", "artist:Queen", "genre:rock"\) | +| `type` | string | Nein | Art der Ergebnisse: track, album, artist, playlist oder durch Komma getrennt \(z.B. "track,artist"\) | +| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Ergebnisse \(1-50\) | +| `offset` | number | Nein | Index des ersten Ergebnisses für die Paginierung | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode zur Filterung der Ergebnisse \(z.B. "US", "GB"\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Liste der passenden Titel | + +### `spotify_get_track` + +Erhalte detaillierte Informationen über einen bestimmten Titel auf Spotify anhand seiner ID. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | Ja | Die Spotify-ID des Titels | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode für die Verfügbarkeit des Titels | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Track-ID | +| `name` | string | Trackname | +| `artists` | array | Liste der Künstler | +| `album` | object | Album-Informationen | +| `duration_ms` | number | Trackdauer in Millisekunden | +| `explicit` | boolean | Ob der Track explizite Inhalte enthält | +| `popularity` | number | Popularitätswert (0-100) | +| `preview_url` | string | URL zur 30-Sekunden-Vorschau | +| `external_url` | string | Spotify-URL | +| `uri` | string | Spotify-URI für den Track | + +### `spotify_get_tracks` + +Erhalte detaillierte Informationen über mehrere Tracks auf Spotify anhand ihrer IDs (bis zu 50). + +#### Input + +| Parameter | Type | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Ja | Kommagetrennte Liste von Spotify-Track-IDs (max. 50) | +| `market` | string | Nein | ISO 3166-1 Alpha-2-Ländercode für Track-Verfügbarkeit | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Liste der Tracks | + +### `spotify_get_album` + +Erhalte detaillierte Informationen über ein Album auf Spotify anhand seiner ID, einschließlich der Trackliste. + +#### Input + +| Parameter | Type | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Ja | Die Spotify-ID des Albums | +| `market` | string | Nein | ISO 3166-1 Alpha-2-Ländercode für Track-Verfügbarkeit | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Album-ID | +| `name` | string | Albumname | +| `artists` | array | Liste der Künstler | +| `album_type` | string | Art des Albums \(album, single, compilation\) | +| `total_tracks` | number | Gesamtanzahl der Tracks | +| `release_date` | string | Veröffentlichungsdatum | +| `label` | string | Plattenlabel | +| `popularity` | number | Popularitätswert \(0-100\) | +| `genres` | array | Liste der Genres | +| `image_url` | string | URL des Albumcovers | +| `tracks` | array | Liste der Tracks auf dem Album | +| `external_url` | string | Spotify-URL | + +### `spotify_get_albums` + +Ruft Details für mehrere Alben anhand ihrer IDs ab. + +#### Input + +| Parameter | Type | Required | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Yes | Durch Kommas getrennte Album-IDs \(max. 20\) | +| `market` | string | No | ISO-Ländercode für den Markt | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `albums` | json | Liste der Alben | + +### `spotify_get_album_tracks` + +Ruft die Tracks eines Albums ab. + +#### Input + +| Parameter | Type | Required | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Yes | Die Spotify-Album-ID | +| `limit` | number | No | Anzahl der zurückzugebenden Tracks \(1-50\) | +| `offset` | number | No | Index des ersten zurückzugebenden Tracks | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | json | Liste der Tracks | +| `total` | number | Gesamtanzahl der Tracks | +| `next` | string | URL für die nächste Seite | + +### `spotify_get_saved_albums` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Alben (1-50) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Albums | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `albums` | json | Liste der gespeicherten Alben | +| `total` | number | Gesamtzahl der gespeicherten Alben | +| `next` | string | URL für die nächste Seite | + +### `spotify_save_albums` + +Alben für den Benutzer speichern + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Ja | Durch Kommas getrennte Album-IDs (max. 20) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Alben gespeichert wurden | + +### `spotify_remove_saved_albums` + +Alben vom Benutzer entfernen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Ja | Durch Kommas getrennte Album-IDs (max. 20) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Alben entfernt wurden | + +### `spotify_check_saved_albums` + +Prüfen, ob Alben in der Bibliothek gespeichert sind. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Ja | Durch Kommas getrennte Album-IDs (max. 20) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jedes Album | + +### `spotify_get_artist` + +Detaillierte Informationen über einen Künstler auf Spotify anhand seiner ID abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Ja | Die Spotify-ID des Künstlers | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Künstler-ID | +| `name` | string | Künstlername | +| `genres` | array | Liste der mit dem Künstler verbundenen Genres | +| `popularity` | number | Popularitätswert (0-100) | +| `followers` | number | Anzahl der Follower | +| `image_url` | string | Künstler-Bild-URL | +| `external_url` | string | Spotify-URL | + +### `spotify_get_artists` + +Details für mehrere Künstler anhand ihrer IDs abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Ja | Durch Kommas getrennte Künstler-IDs (max. 50) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `artists` | json | Liste der Künstler | + +### `spotify_get_artist_albums` + +Alben eines Künstlers auf Spotify abrufen. Kann nach Albumtyp gefiltert werden. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Ja | Die Spotify-ID des Künstlers | +| `include_groups` | string | Nein | Nach Albumtyp filtern: album, single, appears_on, compilation \(durch Komma getrennt\) | +| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Alben \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Albums | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `albums` | array | Künstler | + +### `spotify_get_artist_top_tracks` + +Die 10 beliebtesten Tracks eines Künstlers auf Spotify abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Ja | Die Spotify-ID des Künstlers | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode \(für diesen Endpunkt erforderlich\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Künstler | + +### `spotify_follow_artists` + +Einem oder mehreren Künstlern folgen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Ja | Durch Komma getrennte Künstler-IDs zum Folgen (max. 50) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Künstlern erfolgreich gefolgt wurde | + +### `spotify_unfollow_artists` + +Einem oder mehreren Künstlern entfolgen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Ja | Durch Komma getrennte Künstler-IDs zum Entfolgen (max. 50) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Künstlern erfolgreich entfolgt wurde | + +### `spotify_get_followed_artists` + +Den Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Künstler (1-50) | +| `after` | string | Nein | Cursor für Paginierung (letzte Künstler-ID aus vorheriger Anfrage) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `artists` | json | Liste der gefolgten Künstler | +| `total` | number | Gesamtanzahl der gefolgten Künstler | +| `next` | string | Cursor für die nächste Seite | + +### `spotify_check_following` + +Prüfen, ob der Benutzer Künstlern oder anderen Benutzern folgt. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `type` | string | Ja | Zu prüfender Typ: "artist" oder "user" | +| `ids` | string | Ja | Durch Komma getrennte Künstler- oder Benutzer-IDs (max. 50) | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jede ID | + +### `spotify_get_show` + +Details zu einer Podcast-Show abrufen. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Ja | Die Spotify-Show-ID | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Show-ID | +| `name` | string | Show-Name | +| `description` | string | Show-Beschreibung | +| `publisher` | string | Publisher-Name | +| `total_episodes` | number | Gesamtzahl der Episoden | +| `explicit` | boolean | Enthält explizite Inhalte | +| `languages` | json | Sprachen | +| `image_url` | string | Cover-Bild-URL | +| `external_url` | string | Spotify-URL | + +### `spotify_get_shows` + +Details für mehrere Podcast-Shows abrufen. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Ja | Kommagetrennte Show-IDs \(max. 50\) | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `shows` | json | Liste der Shows | + +### `spotify_get_show_episodes` + +Episoden einer Podcast-Show abrufen. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Ja | Die Spotify-Show-ID | +| `limit` | number | Nein | Anzahl der zurückzugebenden Episoden (1-50) | +| `offset` | number | Nein | Index der ersten zurückzugebenden Episode | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `episodes` | json | Liste der Episoden | +| `total` | number | Gesamtzahl der Episoden | +| `next` | string | URL für die nächste Seite | + +### `spotify_get_saved_shows` + +Benutzer abrufen + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Shows (1-50) | +| `offset` | number | Nein | Index der ersten zurückzugebenden Show | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `shows` | json | Liste der gespeicherten Shows | +| `total` | number | Gesamtzahl der gespeicherten Shows | +| `next` | string | URL für die nächste Seite | + +### `spotify_save_shows` + +Podcast-Shows für den Benutzer speichern + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Ja | Durch Kommas getrennte Show-IDs (max. 50) | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Shows gespeichert wurden | + +### `spotify_remove_saved_shows` + +Podcast-Shows vom Benutzer entfernen + +#### Input + +| Parameter | Type | Required | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Durch Komma getrennte Show-IDs (max. 50) | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Shows entfernt wurden | + +### `spotify_check_saved_shows` + +Prüfen, ob Shows in der Bibliothek gespeichert sind. + +#### Input + +| Parameter | Type | Required | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Yes | Durch Komma getrennte Show-IDs (max. 50) | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jede Show | + +### `spotify_get_episode` + +Details für eine Podcast-Episode abrufen. + +#### Input + +| Parameter | Type | Required | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | Yes | Die Spotify-Episode-ID | +| `market` | string | No | ISO-Ländercode für den Markt | + +#### Output + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Episode-ID | +| `name` | string | Name der Episode | +| `description` | string | Beschreibung der Episode | +| `duration_ms` | number | Dauer in ms | +| `release_date` | string | Veröffentlichungsdatum | +| `explicit` | boolean | Enthält explizite Inhalte | +| `show` | json | Informationen zur übergeordneten Show | +| `image_url` | string | URL des Coverbildes | +| `external_url` | string | Spotify-URL | + +### `spotify_get_episodes` + +Details für mehrere Podcast-Episoden abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Ja | Durch Komma getrennte Episoden-IDs (max. 50) | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `episodes` | json | Liste der Episoden | + +### `spotify_get_saved_episodes` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Episoden (1-50) | +| `offset` | number | Nein | Index der ersten zurückzugebenden Episode | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `episodes` | json | Liste der gespeicherten Episoden | +| `total` | number | Gesamtzahl der gespeicherten Episoden | +| `next` | string | URL für die nächste Seite | + +### `spotify_save_episodes` + +Podcast-Episoden für den Benutzer speichern + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Ja | Durch Komma getrennte Episoden-IDs (max. 50) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Episoden gespeichert wurden | + +### `spotify_remove_saved_episodes` + +Podcast-Episoden vom Benutzer entfernen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Ja | Kommagetrennte Episoden-IDs \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Episoden entfernt wurden | + +### `spotify_check_saved_episodes` + +Prüfen, ob Episoden in der Bibliothek gespeichert sind. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Ja | Kommagetrennte Episoden-IDs \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jede Episode | + +### `spotify_get_audiobook` + +Details für ein Hörbuch abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Ja | Die Spotify-Hörbuch-ID | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Hörbuch-ID | +| `name` | string | Hörbuchname | +| `authors` | json | Autoren | +| `narrators` | json | Sprecher | +| `publisher` | string | Verlag | +| `description` | string | Beschreibung | +| `total_chapters` | number | Gesamtzahl der Kapitel | +| `languages` | json | Sprachen | +| `image_url` | string | Cover-Bild-URL | +| `external_url` | string | Spotify-URL | + +### `spotify_get_audiobooks` + +Erhalte details für mehrere hörbücher. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Ja | Kommagetrennte hörbuch-IDs \(max. 50\) | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `audiobooks` | json | Liste der hörbücher | + +### `spotify_get_audiobook_chapters` + +Erhalte kapitel eines hörbuchs. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Ja | Die Spotify hörbuch-ID | +| `limit` | number | Nein | Anzahl der zurückzugebenden kapitel \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden kapitels | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `chapters` | json | Liste der kapitel | +| `total` | number | Gesamtzahl der kapitel | +| `next` | string | URL für die nächste seite | + +### `spotify_get_saved_audiobooks` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden hörbücher \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden hörbuchs | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `audiobooks` | json | Liste der gespeicherten Hörbücher | +| `total` | number | Gesamtzahl der gespeicherten Hörbücher | +| `next` | string | URL für die nächste Seite | + +### `spotify_save_audiobooks` + +Hörbücher für den Benutzer speichern + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Ja | Durch Kommas getrennte Hörbuch-IDs \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Hörbücher gespeichert wurden | + +### `spotify_remove_saved_audiobooks` + +Hörbücher vom Benutzer entfernen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Ja | Durch Kommas getrennte Hörbuch-IDs \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Hörbücher entfernt wurden | + +### `spotify_check_saved_audiobooks` + +Prüfen, ob Hörbücher in der Bibliothek gespeichert sind. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Ja | Durch Kommas getrennte Hörbuch-IDs \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jedes Hörbuch | + +### `spotify_get_playlist` + +Detaillierte Informationen über eine Playlist auf Spotify anhand ihrer ID abrufen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-ID der Playlist | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode für die Verfügbarkeit des Tracks | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Playlist-ID | +| `name` | string | Playlist-Name | +| `description` | string | Playlist-Beschreibung | +| `public` | boolean | Ob die Playlist öffentlich ist | +| `collaborative` | boolean | Ob die Playlist kollaborativ ist | +| `owner` | object | Informationen zum Playlist-Besitzer | +| `image_url` | string | URL des Playlist-Coverbildes | +| `total_tracks` | number | Gesamtanzahl der Tracks | +| `snapshot_id` | string | Playlist-Snapshot-ID für Versionierung | +| `external_url` | string | Spotify-URL | + +### `spotify_get_playlist_tracks` + +Ruft die Tracks in einer Spotify-Playlist ab. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-ID der Playlist | +| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Tracks (1-100) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Tracks | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode für die Verfügbarkeit des Tracks | + +#### Ausgabe + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Liste der Titel in der Playlist | + +### `spotify_get_playlist_cover` + +Eine Playlist abrufen + +#### Eingabe + +| Parameter | Type | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | + +#### Ausgabe + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `images` | json | Liste der Coverbilder | + +### `spotify_get_user_playlists` + +Den aktuellen Benutzer abrufen + +#### Eingabe + +| Parameter | Type | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Maximale Anzahl der zurückzugebenden Playlists (1-50) | +| `offset` | number | Nein | Index der ersten zurückzugebenden Playlist | + +#### Ausgabe + +| Parameter | Type | Beschreibung | +| --------- | ---- | ----------- | +| `playlists` | array | Benutzer | + +### `spotify_create_playlist` + +Eine neue Playlist für den aktuellen Benutzer auf Spotify erstellen. + +#### Eingabe + +| Parameter | Type | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `name` | string | Ja | Name für die neue Playlist | +| `description` | string | Nein | Beschreibung für die Playlist | +| `public` | boolean | Nein | Ob die Playlist öffentlich sein soll | +| `collaborative` | boolean | Nein | Ob die Playlist kollaborativ sein soll (erfordert, dass öffentlich auf falsch gesetzt ist) | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Playlist-ID | +| `name` | string | Playlist-Name | +| `description` | string | Playlist-Beschreibung | +| `public` | boolean | Ob die Playlist öffentlich ist | +| `collaborative` | boolean | Ob kollaborativ | +| `snapshot_id` | string | Playlist-Snapshot-ID | +| `external_url` | string | Spotify-URL | + +### `spotify_update_playlist` + +Eine Playlist aktualisieren + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `name` | string | Nein | Neuer Name für die Playlist | +| `description` | string | Nein | Neue Beschreibung für die Playlist | +| `public` | boolean | Nein | Ob die Playlist öffentlich sein soll | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Aktualisierung erfolgreich war | + +### `spotify_add_playlist_cover` + +Ein benutzerdefiniertes Coverbild für eine Playlist hochladen. Das Bild muss im JPEG-Format und unter 256 KB sein. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `imageBase64` | string | Ja | Base64-codiertes JPEG-Bild \(max. 256 KB\) | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob der Upload erfolgreich war | + +### `spotify_add_tracks_to_playlist` + +Füge einen oder mehrere Tracks zu einer Spotify-Playlist hinzu. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-ID der Playlist | +| `uris` | string | Ja | Kommagetrennte Spotify-URIs \(z.B. "spotify:track:xxx,spotify:track:yyy"\) | +| `position` | number | Nein | Position zum Einfügen der Tracks \(0-basiert\). Wenn nicht angegeben, werden Tracks angehängt. | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Neue Playlist-Snapshot-ID nach der Änderung | + +### `spotify_remove_tracks_from_playlist` + +Entferne einen oder mehrere Tracks aus einer Spotify-Playlist. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-ID der Playlist | +| `uris` | string | Ja | Kommagetrennte Spotify-URIs zum Entfernen \(z.B. "spotify:track:xxx,spotify:track:yyy"\) | + +#### Output + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Neue Playlist-Snapshot-ID nach der Änderung | + +### `spotify_reorder_playlist_items` + +Verschiebe Tracks an eine andere Position in einer Playlist. + +#### Input + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `range_start` | number | Ja | Startindex der umzusortierenden Elemente | +| `insert_before` | number | Ja | Index, vor dem die Elemente eingefügt werden sollen | +| `range_length` | number | Nein | Anzahl der umzusortierenden Elemente | +| `snapshot_id` | string | Nein | Playlist-Snapshot-ID für Nebenläufigkeitskontrolle | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Neue Playlist-Snapshot-ID | + +### `spotify_replace_playlist_items` + +Ersetzt alle Elemente in einer Playlist durch neue Tracks. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `uris` | string | Ja | Durch Kommas getrennte Spotify-URIs \(max. 100\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Neue Playlist-Snapshot-ID | + +### `spotify_follow_playlist` + +Einer Playlist folgen (speichern). + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `public` | boolean | Nein | Ob die Playlist in öffentlichen Playlists erscheinen soll | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob das Folgen erfolgreich war | + +### `spotify_unfollow_playlist` + +Einer Playlist entfolgen (nicht mehr speichern). + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob das Entfolgen erfolgreich war | + +### `spotify_check_playlist_followers` + +Prüfen, ob Benutzer einer Playlist folgen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Ja | Die Spotify-Playlist-ID | +| `userIds` | string | Ja | Durch Kommas getrennte Benutzer-IDs zur Überprüfung \(max. 5\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Booleschen Werten für jeden Benutzer | + +### `spotify_get_current_user` + +Aktuellen Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Spotify-Benutzer-ID | +| `display_name` | string | Anzeigename | +| `email` | string | E-Mail-Adresse | +| `country` | string | Ländercode | +| `product` | string | Abonnement-Stufe \(free, premium\) | +| `followers` | number | Anzahl der Follower | +| `image_url` | string | Profilbild-URL | +| `external_url` | string | Spotify-Profil-URL | + +### `spotify_get_user_profile` + +Einen Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `userId` | string | Ja | Die Spotify-Benutzer-ID | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `id` | string | Benutzer-ID | +| `display_name` | string | Anzeigename | +| `followers` | number | Anzahl der Follower | +| `image_url` | string | Profilbild-URL | +| `external_url` | string | Spotify-URL | + +### `spotify_get_top_tracks` + +Aktuellen Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | Nein | Zeitraum: short_term \(~4 Wochen\), medium_term \(~6 Monate\), long_term \(Jahre\) | +| `limit` | number | Nein | Anzahl der zurückzugebenden Tracks \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Tracks | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Benutzer | + +### `spotify_get_top_artists` + +Aktuellen Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | Nein | Zeitraum: short_term \(~4 Wochen\), medium_term \(~6 Monate\), long_term \(Jahre\) | +| `limit` | number | Nein | Anzahl der zurückzugebenden Künstler \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Künstlers | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `artists` | array | Benutzer | + +### `spotify_get_saved_tracks` + +Aktuellen Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Tracks \(1-50\) | +| `offset` | number | Nein | Index des ersten zurückzugebenden Tracks | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `tracks` | array | Benutzer | + +### `spotify_save_tracks` + +Tracks für den aktuellen Benutzer speichern + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Ja | Durch Kommas getrennte Spotify-Track-IDs zum Speichern \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Tracks erfolgreich gespeichert wurden | + +### `spotify_remove_saved_tracks` + +Tracks vom Benutzer entfernen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Ja | Durch Kommas getrennte Track-IDs zum Entfernen \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob Tracks erfolgreich entfernt wurden | + +### `spotify_check_saved_tracks` + +Prüfen, ob ein oder mehrere Tracks beim Benutzer gespeichert sind + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Ja | Durch Kommas getrennte Track-IDs zur Überprüfung \(max. 50\) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `results` | json | Array von Track-IDs mit Speicherstatus | +| `all_saved` | boolean | Ob alle Tracks gespeichert sind | +| `none_saved` | boolean | Ob keine Tracks gespeichert sind | + +### `spotify_get_recently_played` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Nein | Anzahl der zurückzugebenden Tracks (1-50) | +| `after` | number | Nein | Unix-Zeitstempel in Millisekunden. Gibt Elemente nach diesem Cursor zurück. | +| `before` | number | Nein | Unix-Zeitstempel in Millisekunden. Gibt Elemente vor diesem Cursor zurück. | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `items` | array | Kürzlich gespielte Tracks | + +### `spotify_get_new_releases` + +Eine Liste neuer Album-Veröffentlichungen abrufen, die bei Spotify vorgestellt werden. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `country` | string | Nein | ISO 3166-1 Alpha-2-Ländercode (z.B. "US", "GB") | +| `limit` | number | Nein | Anzahl der zurückzugebenden Veröffentlichungen (1-50) | +| `offset` | number | Nein | Index der ersten zurückzugebenden Veröffentlichung | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `albums` | json | Liste neuer Veröffentlichungen | +| `total` | number | Gesamtzahl neuer Veröffentlichungen | +| `next` | string | URL für die nächste Seite | + +### `spotify_get_categories` + +Eine Liste von Browse-Kategorien abrufen, die zur Kennzeichnung von Elementen in Spotify verwendet werden. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `country` | string | Nein | ISO 3166-1 Alpha-2-Ländercode (z.B. "US", "GB") | +| `locale` | string | Nein | Locale-Code (z.B. "en_US", "es_MX") | +| `limit` | number | Nein | Anzahl der zurückzugebenden Kategorien (1-50) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `categories` | json | Liste der Durchsuchkategorien | +| `total` | number | Gesamtanzahl der Kategorien | + +### `spotify_get_markets` + +Ruft die Liste der Märkte ab, in denen Spotify verfügbar ist. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `markets` | json | Liste der ISO-Ländercodes | + +### `spotify_get_playback_state` + +Ruft den aktuellen Wiedergabestatus einschließlich Gerät, Titel und Fortschritt ab. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `market` | string | Nein | ISO 3166-1 alpha-2 Ländercode | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Ob die Wiedergabe aktiv ist | +| `device` | object | Informationen zum aktiven Gerät | +| `progress_ms` | number | Fortschritt in Millisekunden | +| `currently_playing_type` | string | Art des abgespielten Inhalts | +| `shuffle_state` | boolean | Ob Zufallswiedergabe aktiviert ist | +| `repeat_state` | string | Wiederholungsmodus \(off, track, context\) | +| `track` | object | Aktuell abgespielter Titel | + +### `spotify_get_currently_playing` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `market` | string | Nein | ISO-Ländercode für den Markt | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Ob die Wiedergabe aktiv ist | +| `progress_ms` | number | Aktuelle Position im Track (ms) | +| `track` | json | Aktuell spielender Track | + +### `spotify_get_devices` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `devices` | array | Verfügbare Wiedergabegeräte | + +### `spotify_get_queue` + +Benutzer abrufen + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `currently_playing` | json | Aktuell spielender Track | +| `queue` | json | Kommende Tracks in der Warteschlange | + +### `spotify_play` + +Starten oder Fortsetzen der Wiedergabe auf Spotify. Kann bestimmte Tracks, Alben oder Playlists abspielen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Nein | Geräte-ID, auf dem abgespielt werden soll. Wenn nicht angegeben, wird auf dem aktiven Gerät abgespielt. | +| `context_uri` | string | Nein | Spotify-URI des Albums, Künstlers oder der Playlist, die abgespielt werden soll (z.B. "spotify:album:xxx") | +| `uris` | string | Nein | Kommagetrennte Track-URIs zum Abspielen (z.B. "spotify:track:xxx,spotify:track:yyy") | +| `offset` | number | Nein | Position im Kontext, an der die Wiedergabe beginnen soll (0-basierter Index) | +| `position_ms` | number | Nein | Position im Track, von der aus gestartet werden soll (in Millisekunden) | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Wiedergabe erfolgreich gestartet wurde | + +### `spotify_pause` + +Wiedergabe auf Spotify pausieren. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Nein | Geräte-ID zum Pausieren. Wenn nicht angegeben, wird das aktive Gerät pausiert. | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Wiedergabe pausiert wurde | + +### `spotify_skip_next` + +Zum nächsten Titel auf Spotify springen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Nein | Geräte-ID. Wenn nicht angegeben, wird das aktive Gerät verwendet. | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob das Überspringen erfolgreich war | + +### `spotify_skip_previous` + +Zum vorherigen Titel auf Spotify springen. + +#### Eingabe + +| Parameter | Typ | Erforderlich | Beschreibung | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Nein | Geräte-ID. Wenn nicht angegeben, wird das aktive Gerät verwendet. | + +#### Ausgabe + +| Parameter | Typ | Beschreibung | +| --------- | ---- | ----------- | +| `success` | boolean | Ob das Überspringen erfolgreich war | + +### `spotify_seek` + +Zu einer Position im aktuell spielenden Titel springen. + +#### Eingabe + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `position_ms` | number | Yes | Position in Millisekunden, zu der gesprungen werden soll | +| `device_id` | string | No | Geräte-ID des Zielgeräts | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob der Sprung erfolgreich war | + +### `spotify_add_to_queue` + +Einen Track zum Benutzer hinzufügen + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `uri` | string | Yes | Spotify URI des hinzuzufügenden Tracks (z.B. "spotify:track:xxx") | +| `device_id` | string | No | Geräte-ID. Wenn nicht angegeben, wird das aktive Gerät verwendet. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob der Track zur Warteschlange hinzugefügt wurde | + +### `spotify_set_volume` + +Die Wiedergabelautstärke auf Spotify einstellen. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `volume_percent` | number | Yes | Lautstärke (0 bis 100) | +| `device_id` | string | No | Geräte-ID. Wenn nicht angegeben, wird das aktive Gerät verwendet. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Lautstärke eingestellt wurde | + +### `spotify_set_repeat` + +Den Wiederholungsmodus für die Wiedergabe einstellen. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `state` | string | Yes | Wiederholungsmodus: "off", "track" oder "context" | +| `device_id` | string | No | Ziel-Geräte-ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob der Wiederholungsmodus erfolgreich eingestellt wurde | + +### `spotify_set_shuffle` + +Zufallswiedergabe ein- oder ausschalten. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `state` | boolean | Yes | true für Zufallswiedergabe ein, false für aus | +| `device_id` | string | No | Ziel-Geräte-ID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Zufallswiedergabe erfolgreich eingestellt wurde | + +### `spotify_transfer_playback` + +Wiedergabe auf ein anderes Gerät übertragen. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Yes | Geräte-ID, auf die die Wiedergabe übertragen werden soll | +| `play` | boolean | No | Ob die Wiedergabe auf dem neuen Gerät gestartet werden soll | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Ob die Übertragung erfolgreich war | + +## Notes + +- Category: `tools` +- Type: `spotify` diff --git a/apps/docs/content/docs/de/tools/zep.mdx b/apps/docs/content/docs/de/tools/zep.mdx index 54d0996794..8c35142ba7 100644 --- a/apps/docs/content/docs/de/tools/zep.mdx +++ b/apps/docs/content/docs/de/tools/zep.mdx @@ -94,10 +94,7 @@ Benutzerkontext aus einem Thread mit Zusammenfassungs- oder Basismodus abrufen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `context` | string | Der Kontextstring \(Zusammenfassung oder Basis\) | -| `facts` | array | Extrahierte Fakten | -| `entities` | array | Extrahierte Entitäten | -| `summary` | string | Konversationszusammenfassung | +| `context` | string | Die Kontext-Zeichenfolge \(Zusammenfassung oder Basismodus\) | ### `zep_get_messages` @@ -137,9 +134,9 @@ Nachrichten zu einem bestehenden Thread hinzufügen | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | -| `context` | string | Aktualisierter Kontext nach dem Hinzufügen von Nachrichten | -| `messageIds` | array | Array der hinzugefügten Nachrichten-UUIDs | | `threadId` | string | Die Thread-ID | +| `added` | boolean | Ob Nachrichten erfolgreich hinzugefügt wurden | +| `messageIds` | array | Array der hinzugefügten Nachrichten-UUIDs | ### `zep_add_user` @@ -209,7 +206,7 @@ Alle Konversations-Threads für einen bestimmten Benutzer auflisten | Parameter | Typ | Beschreibung | | --------- | ---- | ----------- | | `threads` | array | Array von Thread-Objekten für diesen Benutzer | -| `userId` | string | Die Benutzer-ID | +| `totalCount` | number | Gesamtanzahl der zurückgegebenen Threads | ## Hinweise diff --git a/apps/docs/content/docs/es/tools/grafana.mdx b/apps/docs/content/docs/es/tools/grafana.mdx index 8b2d0cd5f2..dec6c45449 100644 --- a/apps/docs/content/docs/es/tools/grafana.mdx +++ b/apps/docs/content/docs/es/tools/grafana.mdx @@ -318,10 +318,10 @@ Crear una anotación en un panel o como una anotación global | --------- | ---- | -------- | ----------- | | `apiKey` | string | Sí | Token de cuenta de servicio de Grafana | | `baseUrl` | string | Sí | URL de la instancia de Grafana \(p. ej., https://your-grafana.com\) | -| `organizationId` | string | No | ID de la organización para instancias de Grafana multi-organización | +| `organizationId` | string | No | ID de organización para instancias Grafana multi-organización | | `text` | string | Sí | El contenido de texto de la anotación | | `tags` | string | No | Lista de etiquetas separadas por comas | -| `dashboardUid` | string | No | UID del panel donde añadir la anotación \(opcional para anotaciones globales\) | +| `dashboardUid` | string | Sí | UID del panel de control donde añadir la anotación | | `panelId` | number | No | ID del panel donde añadir la anotación | | `time` | number | No | Hora de inicio en milisegundos de época \(por defecto es ahora\) | | `timeEnd` | number | No | Hora de finalización en milisegundos de época \(para anotaciones de rango\) | @@ -343,11 +343,11 @@ Consultar anotaciones por rango de tiempo, panel o etiquetas | --------- | ---- | -------- | ----------- | | `apiKey` | string | Sí | Token de cuenta de servicio de Grafana | | `baseUrl` | string | Sí | URL de la instancia de Grafana \(p. ej., https://your-grafana.com\) | -| `organizationId` | string | No | ID de la organización para instancias de Grafana multi-organización | +| `organizationId` | string | No | ID de organización para instancias Grafana multi-organización | | `from` | number | No | Hora de inicio en milisegundos de época | | `to` | number | No | Hora de finalización en milisegundos de época | -| `dashboardUid` | string | No | Filtrar por UID del panel | -| `panelId` | number | No | Filtrar por ID del panel | +| `dashboardUid` | string | Sí | UID del panel de control para consultar anotaciones | +| `panelId` | number | No | Filtrar por ID de panel | | `tags` | string | No | Lista de etiquetas separadas por comas para filtrar | | `type` | string | No | Filtrar por tipo \(alerta o anotación\) | | `limit` | number | No | Número máximo de anotaciones a devolver | @@ -487,6 +487,16 @@ Crear una nueva carpeta en Grafana | `uid` | string | El UID de la carpeta creada | | `title` | string | El título de la carpeta creada | | `url` | string | La ruta URL a la carpeta | +| `hasAcl` | boolean | Si la carpeta tiene permisos ACL personalizados | +| `canSave` | boolean | Si el usuario actual puede guardar la carpeta | +| `canEdit` | boolean | Si el usuario actual puede editar la carpeta | +| `canAdmin` | boolean | Si el usuario actual tiene derechos de administrador en la carpeta | +| `canDelete` | boolean | Si el usuario actual puede eliminar la carpeta | +| `createdBy` | string | Nombre de usuario de quien creó la carpeta | +| `created` | string | Marca de tiempo cuando se creó la carpeta | +| `updatedBy` | string | Nombre de usuario de quien actualizó por última vez la carpeta | +| `updated` | string | Marca de tiempo cuando se actualizó por última vez la carpeta | +| `version` | number | Número de versión de la carpeta | ## Notas diff --git a/apps/docs/content/docs/es/tools/spotify.mdx b/apps/docs/content/docs/es/tools/spotify.mdx new file mode 100644 index 0000000000..ab1d0693fd --- /dev/null +++ b/apps/docs/content/docs/es/tools/spotify.mdx @@ -0,0 +1,1453 @@ +--- +title: Spotify +description: Busca música, gestiona listas de reproducción, controla la + reproducción y accede a tu biblioteca +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Instrucciones de uso + +Integra Spotify en tu flujo de trabajo. Busca canciones, álbumes, artistas y listas de reproducción. Gestiona listas de reproducción, accede a tu biblioteca, controla la reproducción, explora podcasts y audiolibros. + +## Herramientas + +### `spotify_search` + +Busca canciones, álbumes, artistas o listas de reproducción en Spotify. Devuelve resultados coincidentes basados en la consulta. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `query` | string | Sí | Consulta de búsqueda \(p. ej., "Bohemian Rhapsody", "artist:Queen", "genre:rock"\) | +| `type` | string | No | Tipo de resultados: track, album, artist, playlist, o separados por comas \(p. ej., "track,artist"\) | +| `limit` | number | No | Número máximo de resultados a devolver \(1-50\) | +| `offset` | number | No | Índice del primer resultado a devolver para paginación | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para filtrar resultados \(p. ej., "US", "GB"\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Lista de canciones coincidentes | + +### `spotify_get_track` + +Obtén información detallada sobre una canción específica en Spotify mediante su ID. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | Sí | El ID de Spotify de la canción | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para disponibilidad de la canción | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID de pista de Spotify | +| `name` | string | Nombre de la pista | +| `artists` | array | Lista de artistas | +| `album` | object | Información del álbum | +| `duration_ms` | number | Duración de la pista en milisegundos | +| `explicit` | boolean | Si la pista tiene contenido explícito | +| `popularity` | number | Puntuación de popularidad \(0-100\) | +| `preview_url` | string | URL para vista previa de 30 segundos | +| `external_url` | string | URL de Spotify | +| `uri` | string | URI de Spotify para la pista | + +### `spotify_get_tracks` + +Obtén información detallada sobre múltiples pistas en Spotify por sus IDs (hasta 50). + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Sí | Lista de IDs de pistas de Spotify separadas por comas \(máx. 50\) | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para disponibilidad de pistas | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Lista de pistas | + +### `spotify_get_album` + +Obtén información detallada sobre un álbum en Spotify por su ID, incluyendo el listado de pistas. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Sí | El ID de Spotify del álbum | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para disponibilidad de pistas | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID del álbum de Spotify | +| `name` | string | Nombre del álbum | +| `artists` | array | Lista de artistas | +| `album_type` | string | Tipo de álbum \(álbum, sencillo, compilación\) | +| `total_tracks` | number | Número total de pistas | +| `release_date` | string | Fecha de lanzamiento | +| `label` | string | Sello discográfico | +| `popularity` | number | Puntuación de popularidad \(0-100\) | +| `genres` | array | Lista de géneros | +| `image_url` | string | URL de la imagen de portada del álbum | +| `tracks` | array | Lista de pistas del álbum | +| `external_url` | string | URL de Spotify | + +### `spotify_get_albums` + +Obtener detalles de múltiples álbumes por sus IDs. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Sí | IDs de álbumes separados por comas \(máx. 20\) | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `albums` | json | Lista de álbumes | + +### `spotify_get_album_tracks` + +Obtener las pistas de un álbum. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Sí | El ID del álbum de Spotify | +| `limit` | number | No | Número de pistas a devolver \(1-50\) | +| `offset` | number | No | Índice de la primera pista a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | json | Lista de pistas | +| `total` | number | Número total de pistas | +| `next` | string | URL para la siguiente página | + +### `spotify_get_saved_albums` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de álbumes a devolver \(1-50\) | +| `offset` | number | No | Índice del primer álbum a devolver | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `albums` | json | Lista de álbumes guardados | +| `total` | number | Total de álbumes guardados | +| `next` | string | URL para la siguiente página | + +### `spotify_save_albums` + +Guardar álbumes para el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Sí | IDs de álbumes separados por comas \(máx. 20\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los álbumes fueron guardados | + +### `spotify_remove_saved_albums` + +Eliminar álbumes del usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Sí | IDs de álbumes separados por comas \(máx. 20\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si los álbumes fueron eliminados | + +### `spotify_check_saved_albums` + +Comprobar si los álbumes están guardados en la biblioteca. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Sí | IDs de álbumes separados por comas \(máximo 20\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada álbum | + +### `spotify_get_artist` + +Obtener información detallada sobre un artista en Spotify mediante su ID. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Sí | El ID de Spotify del artista | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID del artista en Spotify | +| `name` | string | Nombre del artista | +| `genres` | array | Lista de géneros asociados con el artista | +| `popularity` | number | Puntuación de popularidad \(0-100\) | +| `followers` | number | Número de seguidores | +| `image_url` | string | URL de la imagen del artista | +| `external_url` | string | URL de Spotify | + +### `spotify_get_artists` + +Obtener detalles de múltiples artistas mediante sus IDs. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Sí | IDs de artistas separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `artists` | json | Lista de artistas | + +### `spotify_get_artist_albums` + +Obtener álbumes de un artista en Spotify. Puede filtrar por tipo de álbum. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Sí | El ID de Spotify del artista | +| `include_groups` | string | No | Filtrar por tipo de álbum: album, single, appears_on, compilation \(separados por comas\) | +| `limit` | number | No | Número máximo de álbumes a devolver \(1-50\) | +| `offset` | number | No | Índice del primer álbum a devolver | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `albums` | array | Artista | + +### `spotify_get_artist_top_tracks` + +Obtener las 10 canciones más populares de un artista en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Sí | El ID de Spotify del artista | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 \(obligatorio para este endpoint\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Artista | + +### `spotify_follow_artists` + +Seguir a uno o más artistas. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Sí | IDs de artistas separados por comas para seguir \(máx. 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los artistas fueron seguidos con éxito | + +### `spotify_unfollow_artists` + +Dejar de seguir a uno o más artistas. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Sí | IDs de artistas separados por comas para dejar de seguir \(máx. 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si se dejó de seguir a los artistas con éxito | + +### `spotify_get_followed_artists` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de artistas a devolver \(1-50\) | +| `after` | string | No | Cursor para paginación \(último ID de artista de la solicitud anterior\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `artists` | json | Lista de artistas seguidos | +| `total` | number | Número total de artistas seguidos | +| `next` | string | Cursor para la siguiente página | + +### `spotify_check_following` + +Comprobar si el usuario sigue a artistas o usuarios. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `type` | string | Sí | Tipo a comprobar: "artist" o "user" | +| `ids` | string | Sí | IDs de artistas o usuarios separados por comas \(máx. 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada ID | + +### `spotify_get_show` + +Obtener detalles de un podcast. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Sí | El ID del show de Spotify | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID del show | +| `name` | string | Nombre del show | +| `description` | string | Descripción del show | +| `publisher` | string | Nombre del editor | +| `total_episodes` | number | Total de episodios | +| `explicit` | boolean | Contiene contenido explícito | +| `languages` | json | Idiomas | +| `image_url` | string | URL de la imagen de portada | +| `external_url` | string | URL de Spotify | + +### `spotify_get_shows` + +Obtener detalles de múltiples podcasts. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Sí | IDs de shows separados por comas \(máx. 50\) | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `shows` | json | Lista de shows | + +### `spotify_get_show_episodes` + +Obtener episodios de un programa de podcast. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Sí | El ID del programa de Spotify | +| `limit` | number | No | Número de episodios a devolver \(1-50\) | +| `offset` | number | No | Índice del primer episodio a devolver | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `episodes` | json | Lista de episodios | +| `total` | number | Total de episodios | +| `next` | string | URL para la siguiente página | + +### `spotify_get_saved_shows` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de programas a devolver \(1-50\) | +| `offset` | number | No | Índice del primer programa a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `shows` | json | Lista de programas guardados | +| `total` | number | Total de programas guardados | +| `next` | string | URL para la siguiente página | + +### `spotify_save_shows` + +Guardar programas de podcast para el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Sí | IDs de programas separados por comas \(máx. 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los programas fueron guardados | + +### `spotify_remove_saved_shows` + +Eliminar programas de podcast del usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Sí | IDs de programas separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los programas fueron eliminados | + +### `spotify_check_saved_shows` + +Comprobar si los programas están guardados en la biblioteca. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Sí | IDs de programas separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada programa | + +### `spotify_get_episode` + +Obtener detalles de un episodio de podcast. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | Sí | El ID del episodio de Spotify | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID del episodio | +| `name` | string | Nombre del episodio | +| `description` | string | Descripción del episodio | +| `duration_ms` | number | Duración en ms | +| `release_date` | string | Fecha de lanzamiento | +| `explicit` | boolean | Contiene contenido explícito | +| `show` | json | Información del programa principal | +| `image_url` | string | URL de la imagen de portada | +| `external_url` | string | URL de Spotify | + +### `spotify_get_episodes` + +Obtener detalles de múltiples episodios de podcast. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Sí | IDs de episodios separados por comas (máx. 50) | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `episodes` | json | Lista de episodios | + +### `spotify_get_saved_episodes` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de episodios a devolver (1-50) | +| `offset` | number | No | Índice del primer episodio a devolver | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `episodes` | json | Lista de episodios guardados | +| `total` | number | Total de episodios guardados | +| `next` | string | URL para la siguiente página | + +### `spotify_save_episodes` + +Guardar episodios de podcast para el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Sí | IDs de episodios separados por comas (máx. 50) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los episodios fueron guardados | + +### `spotify_remove_saved_episodes` + +Eliminar episodios de podcast del usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Sí | IDs de episodios separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si los episodios fueron eliminados | + +### `spotify_check_saved_episodes` + +Comprobar si los episodios están guardados en la biblioteca. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Sí | IDs de episodios separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada episodio | + +### `spotify_get_audiobook` + +Obtener detalles de un audiolibro. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Sí | El ID del audiolibro de Spotify | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID del audiolibro | +| `name` | string | Nombre del audiolibro | +| `authors` | json | Autores | +| `narrators` | json | Narradores | +| `publisher` | string | Editorial | +| `description` | string | Descripción | +| `total_chapters` | number | Total de capítulos | +| `languages` | json | Idiomas | +| `image_url` | string | URL de la imagen de portada | +| `external_url` | string | URL de Spotify | + +### `spotify_get_audiobooks` + +Obtener detalles de múltiples audiolibros. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Sí | IDs de audiolibros separados por comas \(máx. 50\) | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `audiobooks` | json | Lista de audiolibros | + +### `spotify_get_audiobook_chapters` + +Obtener capítulos de un audiolibro. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Sí | El ID del audiolibro de Spotify | +| `limit` | number | No | Número de capítulos a devolver \(1-50\) | +| `offset` | number | No | Índice del primer capítulo a devolver | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `chapters` | json | Lista de capítulos | +| `total` | number | Total de capítulos | +| `next` | string | URL para la siguiente página | + +### `spotify_get_saved_audiobooks` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de audiolibros a devolver \(1-50\) | +| `offset` | number | No | Índice del primer audiolibro a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `audiobooks` | json | Lista de audiolibros guardados | +| `total` | number | Total de audiolibros guardados | +| `next` | string | URL para la siguiente página | + +### `spotify_save_audiobooks` + +Guardar audiolibros para el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Sí | IDs de audiolibros separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los audiolibros fueron guardados | + +### `spotify_remove_saved_audiobooks` + +Eliminar audiolibros del usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Sí | IDs de audiolibros separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si los audiolibros fueron eliminados | + +### `spotify_check_saved_audiobooks` + +Comprobar si los audiolibros están guardados en la biblioteca. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Sí | IDs de audiolibros separados por comas \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada audiolibro | + +### `spotify_get_playlist` + +Obtener información detallada sobre una lista de reproducción en Spotify por su ID. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de Spotify de la lista de reproducción | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para la disponibilidad de pistas | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID de la lista de reproducción de Spotify | +| `name` | string | Nombre de la lista de reproducción | +| `description` | string | Descripción de la lista de reproducción | +| `public` | boolean | Si la lista de reproducción es pública | +| `collaborative` | boolean | Si la lista de reproducción es colaborativa | +| `owner` | object | Información del propietario de la lista de reproducción | +| `image_url` | string | URL de la imagen de portada de la lista de reproducción | +| `total_tracks` | number | Número total de pistas | +| `snapshot_id` | string | ID de instantánea de la lista de reproducción para control de versiones | +| `external_url` | string | URL de Spotify | + +### `spotify_get_playlist_tracks` + +Obtener las pistas de una lista de reproducción de Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de Spotify de la lista de reproducción | +| `limit` | number | No | Número máximo de pistas a devolver \(1-100\) | +| `offset` | number | No | Índice de la primera pista a devolver | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 para la disponibilidad de pistas | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Lista de pistas en la lista de reproducción | + +### `spotify_get_playlist_cover` + +Obtener una lista de reproducción + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `images` | json | Lista de imágenes de portada | + +### `spotify_get_user_playlists` + +Obtener el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número máximo de listas de reproducción a devolver \(1-50\) | +| `offset` | number | No | Índice de la primera lista de reproducción a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `playlists` | array | Usuario | + +### `spotify_create_playlist` + +Crear una nueva lista de reproducción para el usuario actual en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `name` | string | Sí | Nombre para la nueva lista de reproducción | +| `description` | string | No | Descripción para la lista de reproducción | +| `public` | boolean | No | Si la lista de reproducción debe ser pública | +| `collaborative` | boolean | No | Si la lista de reproducción debe ser colaborativa \(requiere que public sea false\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID de la lista de reproducción de Spotify | +| `name` | string | Nombre de la lista de reproducción | +| `description` | string | Descripción de la lista de reproducción | +| `public` | boolean | Si la lista de reproducción es pública | +| `collaborative` | boolean | Si es colaborativa | +| `snapshot_id` | string | ID de instantánea de la lista de reproducción | +| `external_url` | string | URL de Spotify | + +### `spotify_update_playlist` + +Actualizar una lista de reproducción + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `name` | string | No | Nuevo nombre para la lista de reproducción | +| `description` | string | No | Nueva descripción para la lista de reproducción | +| `public` | boolean | No | Si la lista de reproducción debe ser pública | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si la actualización tuvo éxito | + +### `spotify_add_playlist_cover` + +Subir una imagen de portada personalizada para una lista de reproducción. La imagen debe ser JPEG y pesar menos de 256KB. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `imageBase64` | string | Sí | Imagen JPEG codificada en Base64 \(máx. 256KB\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si la subida tuvo éxito | + +### `spotify_add_tracks_to_playlist` + +Añadir una o más pistas a una lista de reproducción de Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de Spotify de la lista de reproducción | +| `uris` | string | Sí | URIs de Spotify separadas por comas \(p. ej., "spotify:track:xxx,spotify:track:yyy"\) | +| `position` | number | No | Posición para insertar pistas \(base 0\). Si se omite, las pistas se añaden al final. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nuevo ID de instantánea de la lista de reproducción después de la modificación | + +### `spotify_remove_tracks_from_playlist` + +Eliminar una o más pistas de una lista de reproducción de Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de Spotify de la lista de reproducción | +| `uris` | string | Sí | URIs de Spotify separadas por comas para eliminar \(p. ej., "spotify:track:xxx,spotify:track:yyy"\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nuevo ID de instantánea de la lista de reproducción después de la modificación | + +### `spotify_reorder_playlist_items` + +Mover pistas a una posición diferente en una lista de reproducción. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `range_start` | number | Sí | Índice inicial de los elementos a reordenar | +| `insert_before` | number | Sí | Índice donde insertar los elementos | +| `range_length` | number | No | Número de elementos a reordenar | +| `snapshot_id` | string | No | ID de instantánea de la lista de reproducción para control de concurrencia | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nuevo ID de instantánea de la lista de reproducción | + +### `spotify_replace_playlist_items` + +Reemplazar todos los elementos en una lista de reproducción con nuevas pistas. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `uris` | string | Sí | URIs de Spotify separados por comas \(máximo 100\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nuevo ID de instantánea de la lista de reproducción | + +### `spotify_follow_playlist` + +Seguir (guardar) una lista de reproducción. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `public` | boolean | No | Si la lista de reproducción estará en listas de reproducción públicas | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si el seguimiento tuvo éxito | + +### `spotify_unfollow_playlist` + +Dejar de seguir (eliminar) una lista de reproducción. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si dejar de seguir tuvo éxito | + +### `spotify_check_playlist_followers` + +Comprobar si los usuarios siguen una lista de reproducción. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Sí | El ID de la lista de reproducción de Spotify | +| `userIds` | string | Sí | IDs de usuario separados por comas para verificar \(máximo 5\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de booleanos para cada usuario | + +### `spotify_get_current_user` + +Obtener el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID de usuario de Spotify | +| `display_name` | string | Nombre visible | +| `email` | string | Dirección de correo electrónico | +| `country` | string | Código de país | +| `product` | string | Nivel de suscripción \(gratuito, premium\) | +| `followers` | number | Número de seguidores | +| `image_url` | string | URL de imagen de perfil | +| `external_url` | string | URL del perfil de Spotify | + +### `spotify_get_user_profile` + +Obtener un usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `userId` | string | Sí | El ID de usuario de Spotify | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `id` | string | ID de usuario | +| `display_name` | string | Nombre visible | +| `followers` | number | Número de seguidores | +| `image_url` | string | URL de imagen de perfil | +| `external_url` | string | URL de Spotify | + +### `spotify_get_top_tracks` + +Obtener el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | No | Rango de tiempo: short_term \(~4 semanas\), medium_term \(~6 meses\), long_term \(años\) | +| `limit` | number | No | Número de pistas a devolver \(1-50\) | +| `offset` | number | No | Índice de la primera pista a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Usuario | + +### `spotify_get_top_artists` + +Obtener el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | No | Rango de tiempo: short_term \(~4 semanas\), medium_term \(~6 meses\), long_term \(años\) | +| `limit` | number | No | Número de artistas a devolver \(1-50\) | +| `offset` | number | No | Índice del primer artista a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `artists` | array | Usuario | + +### `spotify_get_saved_tracks` + +Obtener el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de pistas a devolver \(1-50\) | +| `offset` | number | No | Índice de la primera pista a devolver | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `tracks` | array | Usuario | + +### `spotify_save_tracks` + +Guardar pistas para el usuario actual + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Sí | IDs de pistas de Spotify separados por comas para guardar \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si las pistas se guardaron correctamente | + +### `spotify_remove_saved_tracks` + +Eliminar pistas del usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Sí | IDs de pistas separados por comas para eliminar \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Si las pistas se eliminaron correctamente | + +### `spotify_check_saved_tracks` + +Comprobar si una o más pistas están guardadas en el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Sí | IDs de pistas separados por comas para comprobar \(máximo 50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `results` | json | Array de IDs de pistas con estado de guardado | +| `all_saved` | boolean | Si todas las pistas están guardadas | +| `none_saved` | boolean | Si ninguna pista está guardada | + +### `spotify_get_recently_played` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | +| `limit` | number | No | Número de pistas a devolver \(1-50\) | +| `after` | number | No | Marca de tiempo Unix en milisegundos. Devuelve elementos después de este cursor. | +| `before` | number | No | Marca de tiempo Unix en milisegundos. Devuelve elementos antes de este cursor. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `items` | array | Pistas reproducidas recientemente | + +### `spotify_get_new_releases` + +Obtener una lista de nuevos lanzamientos de álbumes destacados en Spotify. + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | +| `country` | string | No | Código de país ISO 3166-1 alpha-2 \(p. ej., "US", "GB"\) | +| `limit` | number | No | Número de lanzamientos a devolver \(1-50\) | +| `offset` | number | No | Índice del primer lanzamiento a devolver | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `albums` | json | Lista de nuevos lanzamientos | +| `total` | number | Número total de nuevos lanzamientos | +| `next` | string | URL para la siguiente página | + +### `spotify_get_categories` + +Obtener una lista de categorías de navegación utilizadas para etiquetar elementos en Spotify. + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | +| `country` | string | No | Código de país ISO 3166-1 alpha-2 \(p. ej., "US", "GB"\) | +| `locale` | string | No | Código de localización \(p. ej., "en_US", "es_MX"\) | +| `limit` | number | No | Número de categorías a devolver \(1-50\) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `categories` | json | Lista de categorías de navegación | +| `total` | number | Número total de categorías | + +### `spotify_get_markets` + +Obtener la lista de mercados donde Spotify está disponible. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `markets` | json | Lista de códigos de país ISO | + +### `spotify_get_playback_state` + +Obtener el estado actual de reproducción incluyendo dispositivo, pista y progreso. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `market` | string | No | Código de país ISO 3166-1 alpha-2 | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Si la reproducción está activa | +| `device` | object | Información del dispositivo activo | +| `progress_ms` | number | Progreso en milisegundos | +| `currently_playing_type` | string | Tipo de contenido en reproducción | +| `shuffle_state` | boolean | Si el modo aleatorio está activado | +| `repeat_state` | string | Modo de repetición (off, track, context) | +| `track` | object | Pista en reproducción actual | + +### `spotify_get_currently_playing` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `market` | string | No | Código de país ISO para el mercado | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Si la reproducción está activa | +| `progress_ms` | number | Posición actual en la pista (ms) | +| `track` | json | Pista reproduciéndose actualmente | + +### `spotify_get_devices` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `devices` | array | Dispositivos de reproducción disponibles | + +### `spotify_get_queue` + +Obtener el usuario + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `currently_playing` | json | Pista reproduciéndose actualmente | +| `queue` | json | Próximas pistas en la cola | + +### `spotify_play` + +Iniciar o reanudar la reproducción en Spotify. Puede reproducir pistas, álbumes o listas de reproducción específicas. + +#### Entrada + +| Parámetro | Tipo | Requerido | Descripción | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | ID del dispositivo para reproducir. Si no se proporciona, reproduce en el dispositivo activo. | +| `context_uri` | string | No | URI de Spotify del álbum, artista o lista de reproducción a reproducir (p. ej., "spotify:album:xxx") | +| `uris` | string | No | URIs de pistas separadas por comas para reproducir (p. ej., "spotify:track:xxx,spotify:track:yyy") | +| `offset` | number | No | Posición en el contexto para comenzar a reproducir (índice basado en 0) | +| `position_ms` | number | No | Posición en la pista para comenzar (en milisegundos) | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si la reproducción comenzó correctamente | + +### `spotify_pause` + +Pausar la reproducción en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | ID del dispositivo para pausar. Si no se proporciona, pausa el dispositivo activo. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si la reproducción fue pausada | + +### `spotify_skip_next` + +Saltar a la siguiente pista en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | ID del dispositivo. Si no se proporciona, usa el dispositivo activo. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si el salto fue exitoso | + +### `spotify_skip_previous` + +Saltar a la pista anterior en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | No | ID del dispositivo. Si no se proporciona, usa el dispositivo activo. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si el salto fue exitoso | + +### `spotify_seek` + +Buscar una posición en la pista que se está reproduciendo actualmente. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `position_ms` | number | Sí | Posición en milisegundos a la que desplazarse | +| `device_id` | string | No | ID del dispositivo objetivo | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si el desplazamiento fue exitoso | + +### `spotify_add_to_queue` + +Añadir una pista al usuario + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `uri` | string | Sí | URI de Spotify de la pista a añadir \(p. ej., "spotify:track:xxx"\) | +| `device_id` | string | No | ID del dispositivo. Si no se proporciona, usa el dispositivo activo. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si la pista fue añadida a la cola | + +### `spotify_set_volume` + +Establecer el volumen de reproducción en Spotify. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `volume_percent` | number | Sí | Nivel de volumen \(0 a 100\) | +| `device_id` | string | No | ID del dispositivo. Si no se proporciona, usa el dispositivo activo. | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si el volumen fue establecido | + +### `spotify_set_repeat` + +Establecer el modo de repetición para la reproducción. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `state` | string | Sí | Modo de repetición: "off", "track", o "context" | +| `device_id` | string | No | ID del dispositivo objetivo | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si el modo de repetición se estableció correctamente | + +### `spotify_set_shuffle` + +Activar o desactivar la reproducción aleatoria. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `state` | boolean | Sí | true para activar la reproducción aleatoria, false para desactivarla | +| `device_id` | string | No | ID del dispositivo objetivo | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si la reproducción aleatoria se estableció correctamente | + +### `spotify_transfer_playback` + +Transferir la reproducción a un dispositivo diferente. + +#### Entrada + +| Parámetro | Tipo | Obligatorio | Descripción | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Sí | ID del dispositivo al que transferir la reproducción | +| `play` | boolean | No | Indica si se debe iniciar la reproducción en el nuevo dispositivo | + +#### Salida + +| Parámetro | Tipo | Descripción | +| --------- | ---- | ----------- | +| `success` | boolean | Indica si la transferencia fue exitosa | + +## Notas + +- Categoría: `tools` +- Tipo: `spotify` diff --git a/apps/docs/content/docs/es/tools/zep.mdx b/apps/docs/content/docs/es/tools/zep.mdx index 9b9e208361..e0ea11b2fa 100644 --- a/apps/docs/content/docs/es/tools/zep.mdx +++ b/apps/docs/content/docs/es/tools/zep.mdx @@ -94,10 +94,7 @@ Recuperar el contexto del usuario de un hilo con modo resumen o básico | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `context` | string | La cadena de contexto \(resumen o básico\) | -| `facts` | array | Hechos extraídos | -| `entities` | array | Entidades extraídas | -| `summary` | string | Resumen de la conversación | +| `context` | string | La cadena de contexto \(modo resumen o básico\) | ### `zep_get_messages` @@ -137,9 +134,9 @@ Añadir mensajes a un hilo existente | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | -| `context` | string | Contexto actualizado después de añadir mensajes | -| `messageIds` | array | Array de UUIDs de mensajes añadidos | | `threadId` | string | El ID del hilo | +| `added` | boolean | Si los mensajes se agregaron correctamente | +| `messageIds` | array | Array de UUIDs de mensajes agregados | ### `zep_add_user` @@ -209,7 +206,7 @@ Listar todos los hilos de conversación para un usuario específico | Parámetro | Tipo | Descripción | | --------- | ---- | ----------- | | `threads` | array | Array de objetos de hilo para este usuario | -| `userId` | string | El ID del usuario | +| `totalCount` | number | Número total de hilos devueltos | ## Notas diff --git a/apps/docs/content/docs/fr/tools/grafana.mdx b/apps/docs/content/docs/fr/tools/grafana.mdx index 04a8bd0176..c8e23b4510 100644 --- a/apps/docs/content/docs/fr/tools/grafana.mdx +++ b/apps/docs/content/docs/fr/tools/grafana.mdx @@ -315,13 +315,13 @@ Créer une annotation sur un tableau de bord ou comme annotation globale #### Entrée | Paramètre | Type | Obligatoire | Description | -| --------- | ---- | ---------- | ----------- | +| --------- | ---- | -------- | ----------- | | `apiKey` | chaîne | Oui | Jeton de compte de service Grafana | | `baseUrl` | chaîne | Oui | URL de l'instance Grafana \(ex., https://your-grafana.com\) | -| `organizationId` | chaîne | Non | ID d'organisation pour les instances Grafana multi-organisations | +| `organizationId` | chaîne | Non | ID de l'organisation pour les instances Grafana multi-organisations | | `text` | chaîne | Oui | Le contenu textuel de l'annotation | -| `tags` | chaîne | Non | Liste de tags séparés par des virgules | -| `dashboardUid` | chaîne | Non | UID du tableau de bord auquel ajouter l'annotation \(facultatif pour les annotations globales\) | +| `tags` | chaîne | Non | Liste d'étiquettes séparées par des virgules | +| `dashboardUid` | chaîne | Oui | UID du tableau de bord auquel ajouter l'annotation | | `panelId` | nombre | Non | ID du panneau auquel ajouter l'annotation | | `time` | nombre | Non | Heure de début en millisecondes d'époque \(par défaut : maintenant\) | | `timeEnd` | nombre | Non | Heure de fin en millisecondes d'époque \(pour les annotations de plage\) | @@ -340,15 +340,15 @@ Interroger les annotations par plage de temps, tableau de bord ou tags #### Entrée | Paramètre | Type | Obligatoire | Description | -| --------- | ---- | ---------- | ----------- | +| --------- | ---- | -------- | ----------- | | `apiKey` | chaîne | Oui | Jeton de compte de service Grafana | | `baseUrl` | chaîne | Oui | URL de l'instance Grafana \(ex., https://your-grafana.com\) | -| `organizationId` | chaîne | Non | ID d'organisation pour les instances Grafana multi-organisations | +| `organizationId` | chaîne | Non | ID de l'organisation pour les instances Grafana multi-organisations | | `from` | nombre | Non | Heure de début en millisecondes d'époque | | `to` | nombre | Non | Heure de fin en millisecondes d'époque | -| `dashboardUid` | chaîne | Non | Filtrer par UID de tableau de bord | +| `dashboardUid` | chaîne | Oui | UID du tableau de bord pour interroger les annotations | | `panelId` | nombre | Non | Filtrer par ID de panneau | -| `tags` | chaîne | Non | Liste de tags séparés par des virgules pour filtrer | +| `tags` | chaîne | Non | Liste d'étiquettes séparées par des virgules pour filtrer | | `type` | chaîne | Non | Filtrer par type \(alerte ou annotation\) | | `limit` | nombre | Non | Nombre maximum d'annotations à retourner | @@ -483,10 +483,20 @@ Créer un nouveau dossier dans Grafana | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `id` | nombre | L'ID numérique du dossier créé | -| `uid` | chaîne | L'UID du dossier créé | -| `title` | chaîne | Le titre du dossier créé | -| `url` | chaîne | Le chemin URL vers le dossier | +| `id` | number | L'identifiant numérique du dossier créé | +| `uid` | string | L'UID du dossier créé | +| `title` | string | Le titre du dossier créé | +| `url` | string | Le chemin URL vers le dossier | +| `hasAcl` | boolean | Si le dossier possède des permissions ACL personnalisées | +| `canSave` | boolean | Si l'utilisateur actuel peut enregistrer le dossier | +| `canEdit` | boolean | Si l'utilisateur actuel peut modifier le dossier | +| `canAdmin` | boolean | Si l'utilisateur actuel a des droits d'administrateur sur le dossier | +| `canDelete` | boolean | Si l'utilisateur actuel peut supprimer le dossier | +| `createdBy` | string | Nom d'utilisateur de la personne qui a créé le dossier | +| `created` | string | Horodatage de la création du dossier | +| `updatedBy` | string | Nom d'utilisateur de la personne qui a dernièrement mis à jour le dossier | +| `updated` | string | Horodatage de la dernière mise à jour du dossier | +| `version` | number | Numéro de version du dossier | ## Notes diff --git a/apps/docs/content/docs/fr/tools/spotify.mdx b/apps/docs/content/docs/fr/tools/spotify.mdx new file mode 100644 index 0000000000..c74a3dba14 --- /dev/null +++ b/apps/docs/content/docs/fr/tools/spotify.mdx @@ -0,0 +1,1453 @@ +--- +title: Spotify +description: Recherchez de la musique, gérez des playlists, contrôlez la lecture + et accédez à votre bibliothèque +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Instructions d'utilisation + +Intégrez Spotify dans votre flux de travail. Recherchez des morceaux, albums, artistes et playlists. Gérez des playlists, accédez à votre bibliothèque, contrôlez la lecture, parcourez les podcasts et les livres audio. + +## Outils + +### `spotify_search` + +Recherchez des morceaux, albums, artistes ou playlists sur Spotify. Renvoie les résultats correspondants basés sur la requête. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `query` | string | Oui | Requête de recherche \(ex. : "Bohemian Rhapsody", "artist:Queen", "genre:rock"\) | +| `type` | string | Non | Type de résultats : track, album, artist, playlist, ou séparés par virgules \(ex. : "track,artist"\) | +| `limit` | number | Non | Nombre maximum de résultats à renvoyer \(1-50\) | +| `offset` | number | Non | Index du premier résultat à renvoyer pour la pagination | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 pour filtrer les résultats \(ex. : "US", "GB"\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Liste des morceaux correspondants | + +### `spotify_get_track` + +Obtenez des informations détaillées sur un morceau spécifique sur Spotify par son ID. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | Oui | L'ID Spotify du morceau | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 pour la disponibilité du morceau | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID de piste Spotify | +| `name` | string | Nom de la piste | +| `artists` | array | Liste des artistes | +| `album` | object | Informations sur l'album | +| `duration_ms` | number | Durée de la piste en millisecondes | +| `explicit` | boolean | Si la piste contient du contenu explicite | +| `popularity` | number | Score de popularité (0-100) | +| `preview_url` | string | URL vers un aperçu de 30 secondes | +| `external_url` | string | URL Spotify | +| `uri` | string | URI Spotify pour la piste | + +### `spotify_get_tracks` + +Obtenir des informations détaillées sur plusieurs pistes Spotify par leurs identifiants (jusqu'à 50). + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Oui | Liste d'identifiants de pistes Spotify séparés par des virgules (max 50) | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 pour la disponibilité des pistes | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Liste des pistes | + +### `spotify_get_album` + +Obtenir des informations détaillées sur un album Spotify par son identifiant, y compris la liste des pistes. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | Oui | L'identifiant Spotify de l'album | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 pour la disponibilité des pistes | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID d'album Spotify | +| `name` | string | Nom de l'album | +| `artists` | array | Liste des artistes | +| `album_type` | string | Type d'album \(album, single, compilation\) | +| `total_tracks` | number | Nombre total de pistes | +| `release_date` | string | Date de sortie | +| `label` | string | Maison de disques | +| `popularity` | number | Score de popularité \(0-100\) | +| `genres` | array | Liste des genres | +| `image_url` | string | URL de l'image de couverture de l'album | +| `tracks` | array | Liste des pistes de l'album | +| `external_url` | string | URL Spotify | + +### `spotify_get_albums` + +Obtenir les détails de plusieurs albums par leurs identifiants. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `albumIds` | string | Oui | Identifiants d'albums séparés par des virgules \(max 20\) | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | Liste des albums | + +### `spotify_get_album_tracks` + +Obtenir les pistes d'un album. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `albumId` | string | Oui | L'identifiant de l'album Spotify | +| `limit` | number | Non | Nombre de pistes à retourner \(1-50\) | +| `offset` | number | Non | Index de la première piste à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | json | Liste des pistes | +| `total` | number | Nombre total de pistes | +| `next` | string | URL pour la page suivante | + +### `spotify_get_saved_albums` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Non | Nombre d'albums à retourner \(1-50\) | +| `offset` | number | Non | Index du premier album à retourner | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | Liste des albums sauvegardés | +| `total` | number | Total des albums sauvegardés | +| `next` | string | URL pour la page suivante | + +### `spotify_save_albums` + +Sauvegarder des albums pour l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Oui | IDs d'albums séparés par des virgules \(max 20\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si les albums ont été sauvegardés | + +### `spotify_remove_saved_albums` + +Supprimer des albums de l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Oui | IDs d'albums séparés par des virgules \(max 20\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les albums ont été supprimés | + +### `spotify_check_saved_albums` + +Vérifier si les albums sont enregistrés dans la bibliothèque. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | Oui | IDs d'albums séparés par des virgules (max 20) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque album | + +### `spotify_get_artist` + +Obtenir des informations détaillées sur un artiste Spotify à partir de son ID. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Oui | L'ID Spotify de l'artiste | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID de l'artiste Spotify | +| `name` | string | Nom de l'artiste | +| `genres` | array | Liste des genres associés à l'artiste | +| `popularity` | number | Score de popularité (0-100) | +| `followers` | number | Nombre d'abonnés | +| `image_url` | string | URL de l'image de l'artiste | +| `external_url` | string | URL Spotify | + +### `spotify_get_artists` + +Obtenir les détails de plusieurs artistes à partir de leurs IDs. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | Oui | IDs d'artistes séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `artists` | json | Liste des artistes | + +### `spotify_get_artist_albums` + +Obtenir les albums d'un artiste sur Spotify. Peut filtrer par type d'album. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Oui | L'identifiant Spotify de l'artiste | +| `include_groups` | string | Non | Filtrer par type d'album : album, single, appears_on, compilation \(séparés par des virgules\) | +| `limit` | number | Non | Nombre maximum d'albums à retourner \(1-50\) | +| `offset` | number | Non | Index du premier album à retourner | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `albums` | array | Artiste | + +### `spotify_get_artist_top_tracks` + +Obtenir les 10 titres les plus populaires d'un artiste sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | Oui | L'identifiant Spotify de l'artiste | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 \(requis pour ce point de terminaison\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Artiste | + +### `spotify_follow_artists` + +Suivre un ou plusieurs artistes. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `artistIds` | string | Oui | IDs d'artistes séparés par des virgules à suivre (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les artistes ont été suivis avec succès | + +### `spotify_unfollow_artists` + +Ne plus suivre un ou plusieurs artistes. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `artistIds` | string | Oui | IDs d'artistes séparés par des virgules à ne plus suivre (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les artistes ont été retirés des suivis avec succès | + +### `spotify_get_followed_artists` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `limit` | number | Non | Nombre d'artistes à retourner (1-50) | +| `after` | string | Non | Curseur pour la pagination (dernier ID d'artiste de la requête précédente) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `artists` | json | Liste des artistes suivis | +| `total` | number | Nombre total d'artistes suivis | +| `next` | string | Curseur pour la page suivante | + +### `spotify_check_following` + +Vérifier si l'utilisateur suit des artistes ou d'autres utilisateurs. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `type` | string | Oui | Type à vérifier : "artist" ou "user" | +| `ids` | string | Oui | IDs d'artistes ou d'utilisateurs séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque ID | + +### `spotify_get_show` + +Obtenir les détails d'une émission de podcast. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `showId` | string | Oui | L'ID de l'émission Spotify | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID de l'émission | +| `name` | string | Nom de l'émission | +| `description` | string | Description de l'émission | +| `publisher` | string | Nom de l'éditeur | +| `total_episodes` | number | Nombre total d'épisodes | +| `explicit` | boolean | Contient du contenu explicite | +| `languages` | json | Langues | +| `image_url` | string | URL de l'image de couverture | +| `external_url` | string | URL Spotify | + +### `spotify_get_shows` + +Obtenir les détails de plusieurs émissions de podcast. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Oui | IDs d'émissions séparés par des virgules \(max 50\) | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `shows` | json | Liste des émissions | + +### `spotify_get_show_episodes` + +Obtenir les épisodes d'une émission de podcast. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `showId` | string | Oui | L'identifiant Spotify de l'émission | +| `limit` | number | Non | Nombre d'épisodes à retourner \(1-50\) | +| `offset` | number | Non | Index du premier épisode à retourner | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | Liste des épisodes | +| `total` | number | Nombre total d'épisodes | +| `next` | string | URL pour la page suivante | + +### `spotify_get_saved_shows` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `limit` | number | Non | Nombre d'émissions à retourner \(1-50\) | +| `offset` | number | Non | Index de la première émission à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `shows` | json | Liste des émissions enregistrées | +| `total` | number | Nombre total d'émissions enregistrées | +| `next` | string | URL pour la page suivante | + +### `spotify_save_shows` + +Enregistrer des émissions de podcast pour l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `showIds` | string | Oui | Identifiants d'émissions séparés par des virgules \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les émissions ont été enregistrées | + +### `spotify_remove_saved_shows` + +Supprimer des émissions de podcast de l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Oui | IDs d'émissions séparés par des virgules \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les émissions ont été supprimées | + +### `spotify_check_saved_shows` + +Vérifier si les émissions sont enregistrées dans la bibliothèque. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | Oui | IDs d'émissions séparés par des virgules \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque émission | + +### `spotify_get_episode` + +Obtenir les détails d'un épisode de podcast. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | Oui | L'ID de l'épisode Spotify | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID de l'épisode | +| `name` | string | Nom de l'épisode | +| `description` | string | Description de l'épisode | +| `duration_ms` | number | Durée en ms | +| `release_date` | string | Date de sortie | +| `explicit` | boolean | Contient du contenu explicite | +| `show` | json | Informations sur l'émission parente | +| `image_url` | string | URL de l'image de couverture | +| `external_url` | string | URL Spotify | + +### `spotify_get_episodes` + +Obtenir les détails de plusieurs épisodes de podcast. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `episodeIds` | chaîne | Oui | IDs d'épisodes séparés par des virgules \(max 50\) | +| `market` | chaîne | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | Liste des épisodes | + +### `spotify_get_saved_episodes` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `limit` | nombre | Non | Nombre d'épisodes à retourner \(1-50\) | +| `offset` | nombre | Non | Index du premier épisode à retourner | +| `market` | chaîne | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `episodes` | json | Liste des épisodes enregistrés | +| `total` | nombre | Total des épisodes enregistrés | +| `next` | chaîne | URL pour la page suivante | + +### `spotify_save_episodes` + +Enregistrer des épisodes de podcast pour l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `episodeIds` | chaîne | Oui | IDs d'épisodes séparés par des virgules \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | booléen | Si les épisodes ont été enregistrés | + +### `spotify_remove_saved_episodes` + +Supprimer des épisodes de podcast de l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Oui | IDs d'épisodes séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les épisodes ont été supprimés | + +### `spotify_check_saved_episodes` + +Vérifier si les épisodes sont enregistrés dans la bibliothèque. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | Oui | IDs d'épisodes séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque épisode | + +### `spotify_get_audiobook` + +Obtenir les détails d'un livre audio. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | Oui | L'ID du livre audio Spotify | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID du livre audio | +| `name` | string | Nom du livre audio | +| `authors` | json | Auteurs | +| `narrators` | json | Narrateurs | +| `publisher` | string | Éditeur | +| `description` | string | Description | +| `total_chapters` | number | Nombre total de chapitres | +| `languages` | json | Langues | +| `image_url` | string | URL de l'image de couverture | +| `external_url` | string | URL Spotify | + +### `spotify_get_audiobooks` + +Obtenir les détails de plusieurs livres audio. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `audiobookIds` | chaîne | Oui | IDs de livres audio séparés par des virgules \(max 50\) | +| `market` | chaîne | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `audiobooks` | json | Liste des livres audio | + +### `spotify_get_audiobook_chapters` + +Obtenir les chapitres d'un livre audio. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `audiobookId` | chaîne | Oui | L'ID Spotify du livre audio | +| `limit` | nombre | Non | Nombre de chapitres à retourner \(1-50\) | +| `offset` | nombre | Non | Index du premier chapitre à retourner | +| `market` | chaîne | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `chapters` | json | Liste des chapitres | +| `total` | nombre | Total des chapitres | +| `next` | chaîne | URL pour la page suivante | + +### `spotify_get_saved_audiobooks` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `limit` | nombre | Non | Nombre de livres audio à retourner \(1-50\) | +| `offset` | nombre | Non | Index du premier livre audio à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `audiobooks` | json | Liste des livres audio enregistrés | +| `total` | number | Nombre total de livres audio enregistrés | +| `next` | string | URL pour la page suivante | + +### `spotify_save_audiobooks` + +Enregistrer des livres audio pour l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Oui | IDs de livres audio séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les livres audio ont été enregistrés | + +### `spotify_remove_saved_audiobooks` + +Supprimer des livres audio de l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Oui | IDs de livres audio séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si les livres audio ont été supprimés | + +### `spotify_check_saved_audiobooks` + +Vérifier si les livres audio sont enregistrés dans la bibliothèque. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | Oui | IDs de livres audio séparés par des virgules (max 50) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque livre audio | + +### `spotify_get_playlist` + +Obtenir des informations détaillées sur une playlist Spotify par son ID. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `playlistId` | chaîne | Oui | L'identifiant Spotify de la playlist | +| `market` | chaîne | Non | Code pays ISO 3166-1 alpha-2 pour la disponibilité des pistes | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | chaîne | Identifiant de la playlist Spotify | +| `name` | chaîne | Nom de la playlist | +| `description` | chaîne | Description de la playlist | +| `public` | booléen | Si la playlist est publique | +| `collaborative` | booléen | Si la playlist est collaborative | +| `owner` | objet | Informations sur le propriétaire de la playlist | +| `image_url` | chaîne | URL de l'image de couverture de la playlist | +| `total_tracks` | nombre | Nombre total de pistes | +| `snapshot_id` | chaîne | ID d'instantané de la playlist pour le versionnement | +| `external_url` | chaîne | URL Spotify | + +### `spotify_get_playlist_tracks` + +Obtenir les pistes d'une playlist Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `playlistId` | chaîne | Oui | L'identifiant Spotify de la playlist | +| `limit` | nombre | Non | Nombre maximum de pistes à retourner \(1-100\) | +| `offset` | nombre | Non | Index de la première piste à retourner | +| `market` | chaîne | Non | Code pays ISO 3166-1 alpha-2 pour la disponibilité des pistes | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Liste des pistes dans la playlist | + +### `spotify_get_playlist_cover` + +Obtenir une playlist + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `playlistId` | string | Oui | L'identifiant Spotify de la playlist | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `images` | json | Liste des images de couverture | + +### `spotify_get_user_playlists` + +Obtenir l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `limit` | number | Non | Nombre maximum de playlists à retourner \(1-50\) | +| `offset` | number | Non | Index de la première playlist à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `playlists` | array | Utilisateur | + +### `spotify_create_playlist` + +Créer une nouvelle playlist pour l'utilisateur actuel sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `name` | string | Oui | Nom de la nouvelle playlist | +| `description` | string | Non | Description de la playlist | +| `public` | boolean | Non | Si la playlist doit être publique | +| `collaborative` | boolean | Non | Si la playlist doit être collaborative \(nécessite que public soit défini sur false\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | ID de la playlist Spotify | +| `name` | string | Nom de la playlist | +| `description` | string | Description de la playlist | +| `public` | boolean | Si la playlist est publique | +| `collaborative` | boolean | Si collaborative | +| `snapshot_id` | string | ID d'instantané de la playlist | +| `external_url` | string | URL Spotify | + +### `spotify_update_playlist` + +Mettre à jour une playlist + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'ID de la playlist Spotify | +| `name` | string | Non | Nouveau nom pour la playlist | +| `description` | string | Non | Nouvelle description pour la playlist | +| `public` | boolean | Non | Si la playlist doit être publique | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si la mise à jour a réussi | + +### `spotify_add_playlist_cover` + +Télécharger une image de couverture personnalisée pour une playlist. L'image doit être au format JPEG et inférieure à 256 Ko. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'ID de la playlist Spotify | +| `imageBase64` | string | Oui | Image JPEG encodée en Base64 \(max 256 Ko\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si le téléchargement a réussi | + +### `spotify_add_tracks_to_playlist` + +Ajouter une ou plusieurs pistes à une playlist Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `playlistId` | string | Oui | L'identifiant Spotify de la playlist | +| `uris` | string | Oui | URIs Spotify séparées par des virgules \(ex., "spotify:track:xxx,spotify:track:yyy"\) | +| `position` | number | Non | Position pour insérer les pistes \(à partir de 0\). Si omis, les pistes sont ajoutées à la fin. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nouvel identifiant d'instantané de playlist après modification | + +### `spotify_remove_tracks_from_playlist` + +Supprimer une ou plusieurs pistes d'une playlist Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `playlistId` | string | Oui | L'identifiant Spotify de la playlist | +| `uris` | string | Oui | URIs Spotify séparées par des virgules à supprimer \(ex., "spotify:track:xxx,spotify:track:yyy"\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nouvel identifiant d'instantané de playlist après modification | + +### `spotify_reorder_playlist_items` + +Déplacer des pistes vers une position différente dans une playlist. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `playlistId` | string | Oui | L'identifiant de la playlist Spotify | +| `range_start` | number | Oui | Index de départ des éléments à réorganiser | +| `insert_before` | number | Oui | Index avant lequel insérer les éléments | +| `range_length` | number | Non | Nombre d'éléments à réorganiser | +| `snapshot_id` | string | Non | Identifiant d'instantané de playlist pour le contrôle de concurrence | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nouvel ID d'instantané de playlist | + +### `spotify_replace_playlist_items` + +Remplacer tous les éléments d'une playlist par de nouvelles pistes. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'ID de playlist Spotify | +| `uris` | string | Oui | URIs Spotify séparées par des virgules \(max 100\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `snapshot_id` | string | Nouvel ID d'instantané de playlist | + +### `spotify_follow_playlist` + +Suivre (sauvegarder) une playlist. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'ID de playlist Spotify | +| `public` | boolean | Non | Si la playlist sera dans les playlists publiques | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si le suivi a réussi | + +### `spotify_unfollow_playlist` + +Ne plus suivre (désauvegarder) une playlist. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'ID de playlist Spotify | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si le désabonnement a réussi | + +### `spotify_check_playlist_followers` + +Vérifier si les utilisateurs suivent une playlist. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | Oui | L'identifiant de la playlist Spotify | +| `userIds` | string | Oui | Identifiants d'utilisateurs séparés par des virgules à vérifier \(max 5\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau de booléens pour chaque utilisateur | + +### `spotify_get_current_user` + +Obtenir l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Identifiant d'utilisateur Spotify | +| `display_name` | string | Nom d'affichage | +| `email` | string | Adresse e-mail | +| `country` | string | Code pays | +| `product` | string | Niveau d'abonnement \(gratuit, premium\) | +| `followers` | number | Nombre d'abonnés | +| `image_url` | string | URL de l'image de profil | +| `external_url` | string | URL du profil Spotify | + +### `spotify_get_user_profile` + +Obtenir un utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `userId` | string | Oui | L'identifiant d'utilisateur Spotify | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Identifiant d'utilisateur | +| `display_name` | string | Nom d'affichage | +| `followers` | number | Nombre d'abonnés | +| `image_url` | string | URL de l'image de profil | +| `external_url` | string | URL Spotify | + +### `spotify_get_top_tracks` + +Obtenir l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | Non | Période : short_term \(~4 semaines\), medium_term \(~6 mois\), long_term \(années\) | +| `limit` | number | Non | Nombre de pistes à retourner \(1-50\) | +| `offset` | number | Non | Index de la première piste à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Utilisateur | + +### `spotify_get_top_artists` + +Obtenir l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | Non | Période : short_term \(~4 semaines\), medium_term \(~6 mois\), long_term \(années\) | +| `limit` | number | Non | Nombre d'artistes à retourner \(1-50\) | +| `offset` | number | Non | Index du premier artiste à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `artists` | array | Utilisateur | + +### `spotify_get_saved_tracks` + +Obtenir l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Non | Nombre de pistes à retourner \(1-50\) | +| `offset` | number | Non | Index de la première piste à retourner | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `tracks` | array | Utilisateur | + +### `spotify_save_tracks` + +Enregistrer des pistes pour l'utilisateur actuel + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Oui | IDs de pistes Spotify séparés par des virgules à enregistrer \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si les pistes ont été enregistrées avec succès | + +### `spotify_remove_saved_tracks` + +Supprimer des pistes de l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Oui | IDs de pistes séparés par des virgules à supprimer \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Si les pistes ont été supprimées avec succès | + +### `spotify_check_saved_tracks` + +Vérifier si une ou plusieurs pistes sont enregistrées chez l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | Oui | IDs de pistes séparés par des virgules à vérifier \(max 50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `results` | json | Tableau d'IDs de pistes avec leur statut d'enregistrement | +| `all_saved` | boolean | Si toutes les pistes sont enregistrées | +| `none_saved` | boolean | Si aucune piste n'est enregistrée | + +### `spotify_get_recently_played` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `limit` | number | Non | Nombre de pistes à retourner \(1-50\) | +| `after` | number | Non | Timestamp Unix en millisecondes. Renvoie les éléments après ce curseur. | +| `before` | number | Non | Timestamp Unix en millisecondes. Renvoie les éléments avant ce curseur. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `items` | array | Pistes écoutées récemment | + +### `spotify_get_new_releases` + +Obtenir une liste des nouvelles sorties d'albums mises en avant sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `country` | string | Non | Code pays ISO 3166-1 alpha-2 \(ex., "US", "GB"\) | +| `limit` | number | Non | Nombre de sorties à retourner \(1-50\) | +| `offset` | number | Non | Index de la première sortie à retourner | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `albums` | json | Liste des nouvelles sorties | +| `total` | number | Nombre total de nouvelles sorties | +| `next` | string | URL pour la page suivante | + +### `spotify_get_categories` + +Obtenir une liste des catégories de navigation utilisées pour étiqueter les éléments dans Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `country` | string | Non | Code pays ISO 3166-1 alpha-2 \(ex., "US", "GB"\) | +| `locale` | string | Non | Code de langue \(ex., "en_US", "es_MX"\) | +| `limit` | number | Non | Nombre de catégories à retourner \(1-50\) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `categories` | json | Liste des catégories de navigation | +| `total` | number | Nombre total de catégories | + +### `spotify_get_markets` + +Obtenir la liste des marchés où Spotify est disponible. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `markets` | json | Liste des codes pays ISO | + +### `spotify_get_playback_state` + +Obtenir l'état de lecture actuel, y compris l'appareil, la piste et la progression. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `market` | string | Non | Code pays ISO 3166-1 alpha-2 | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Si la lecture est active | +| `device` | object | Informations sur l'appareil actif | +| `progress_ms` | number | Progression en millisecondes | +| `currently_playing_type` | string | Type de contenu en lecture | +| `shuffle_state` | boolean | Si la lecture aléatoire est activée | +| `repeat_state` | string | Mode de répétition (off, track, context) | +| `track` | object | Piste en cours de lecture | + +### `spotify_get_currently_playing` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `market` | string | Non | Code pays ISO pour le marché | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `is_playing` | boolean | Indique si la lecture est active | +| `progress_ms` | number | Position actuelle dans la piste (ms) | +| `track` | json | Piste en cours de lecture | + +### `spotify_get_devices` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `devices` | array | Appareils de lecture disponibles | + +### `spotify_get_queue` + +Obtenir l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `currently_playing` | json | Piste en cours de lecture | +| `queue` | json | Pistes à venir dans la file d'attente | + +### `spotify_play` + +Démarrer ou reprendre la lecture sur Spotify. Peut lire des pistes, albums ou playlists spécifiques. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ----------- | ----------- | +| `device_id` | string | Non | ID de l'appareil sur lequel lancer la lecture. Si non fourni, la lecture se fait sur l'appareil actif. | +| `context_uri` | string | Non | URI Spotify de l'album, artiste ou playlist à lire (ex. : "spotify:album:xxx") | +| `uris` | string | Non | URIs des pistes séparées par des virgules à lire (ex. : "spotify:track:xxx,spotify:track:yyy") | +| `offset` | number | Non | Position dans le contexte pour commencer la lecture (index basé sur 0) | +| `position_ms` | number | Non | Position dans la piste pour commencer (en millisecondes) | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si la lecture a démarré avec succès | + +### `spotify_pause` + +Mettre en pause la lecture sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Non | ID de l'appareil à mettre en pause. Si non fourni, met en pause l'appareil actif. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si la lecture a été mise en pause | + +### `spotify_skip_next` + +Passer à la piste suivante sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Non | ID de l'appareil. Si non fourni, utilise l'appareil actif. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le passage à la piste suivante a réussi | + +### `spotify_skip_previous` + +Revenir à la piste précédente sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | Non | ID de l'appareil. Si non fourni, utilise l'appareil actif. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le retour à la piste précédente a réussi | + +### `spotify_seek` + +Se positionner à un moment précis dans la piste en cours de lecture. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `position_ms` | number | Oui | Position en millisecondes vers laquelle se déplacer | +| `device_id` | string | Non | ID de l'appareil ciblé | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le déplacement a réussi | + +### `spotify_add_to_queue` + +Ajouter une piste à l'utilisateur + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `uri` | string | Oui | URI Spotify de la piste à ajouter \(ex. : "spotify:track:xxx"\) | +| `device_id` | string | Non | ID de l'appareil. Si non fourni, utilise l'appareil actif. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si la piste a été ajoutée à la file d'attente | + +### `spotify_set_volume` + +Régler le volume de lecture sur Spotify. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `volume_percent` | number | Oui | Niveau de volume \(0 à 100\) | +| `device_id` | string | Non | ID de l'appareil. Si non fourni, utilise l'appareil actif. | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le volume a été réglé | + +### `spotify_set_repeat` + +Définir le mode de répétition pour la lecture. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `state` | string | Oui | Mode répétition : "off", "track" ou "context" | +| `device_id` | string | Non | ID de l'appareil ciblé | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le mode répétition a été défini avec succès | + +### `spotify_set_shuffle` + +Activer ou désactiver la lecture aléatoire. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `state` | boolean | Oui | true pour activer la lecture aléatoire, false pour la désactiver | +| `device_id` | string | Non | ID de l'appareil ciblé | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si la lecture aléatoire a été définie avec succès | + +### `spotify_transfer_playback` + +Transférer la lecture vers un autre appareil. + +#### Entrée + +| Paramètre | Type | Obligatoire | Description | +| --------- | ---- | ---------- | ----------- | +| `device_id` | string | Oui | ID de l'appareil vers lequel transférer la lecture | +| `play` | boolean | Non | Indique s'il faut démarrer la lecture sur le nouvel appareil | + +#### Sortie + +| Paramètre | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Indique si le transfert a réussi | + +## Notes + +- Catégorie : `tools` +- Type : `spotify` diff --git a/apps/docs/content/docs/fr/tools/zep.mdx b/apps/docs/content/docs/fr/tools/zep.mdx index ba60852b46..3b107ea1b4 100644 --- a/apps/docs/content/docs/fr/tools/zep.mdx +++ b/apps/docs/content/docs/fr/tools/zep.mdx @@ -94,10 +94,7 @@ Récupérer le contexte utilisateur d'un fil de discussion en mode résumé ou b | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `context` | string | La chaîne de contexte \(résumé ou basique\) | -| `facts` | array | Faits extraits | -| `entities` | array | Entités extraites | -| `summary` | string | Résumé de la conversation | +| `context` | string | La chaîne de contexte \(mode résumé ou basique\) | ### `zep_get_messages` @@ -137,9 +134,9 @@ Ajouter des messages à un fil de discussion existant | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `context` | chaîne | Contexte mis à jour après l'ajout des messages | -| `messageIds` | tableau | Tableau des UUID des messages ajoutés | -| `threadId` | chaîne | L'ID du fil de discussion | +| `threadId` | string | L'ID du fil de discussion | +| `added` | boolean | Si les messages ont été ajoutés avec succès | +| `messageIds` | array | Tableau des UUID des messages ajoutés | ### `zep_add_user` @@ -208,8 +205,8 @@ Lister tous les fils de conversation pour un utilisateur spécifique | Paramètre | Type | Description | | --------- | ---- | ----------- | -| `threads` | tableau | Tableau d'objets de fils pour cet utilisateur | -| `userId` | chaîne | L'ID de l'utilisateur | +| `threads` | array | Tableau d'objets de fil de discussion pour cet utilisateur | +| `totalCount` | number | Nombre total de fils de discussion retournés | ## Notes diff --git a/apps/docs/content/docs/ja/tools/grafana.mdx b/apps/docs/content/docs/ja/tools/grafana.mdx index 50b2531418..bd3f9e9b70 100644 --- a/apps/docs/content/docs/ja/tools/grafana.mdx +++ b/apps/docs/content/docs/ja/tools/grafana.mdx @@ -321,9 +321,9 @@ UIDによるアラートルールの削除 | `organizationId` | string | いいえ | マルチ組織Grafanaインスタンス用の組織ID | | `text` | string | はい | アノテーションのテキスト内容 | | `tags` | string | いいえ | カンマ区切りのタグリスト | -| `dashboardUid` | string | いいえ | アノテーションを追加するダッシュボードのUID(全体的なアノテーションの場合はオプション) | +| `dashboardUid` | string | はい | アノテーションを追加するダッシュボードのUID | | `panelId` | number | いいえ | アノテーションを追加するパネルのID | -| `time` | number | いいえ | エポックミリ秒での開始時間(デフォルトは現在) | +| `time` | number | いいえ | エポックミリ秒での開始時間(デフォルトは現在時刻) | | `timeEnd` | number | いいえ | エポックミリ秒での終了時間(範囲アノテーション用) | #### 出力 @@ -346,10 +346,10 @@ UIDによるアラートルールの削除 | `organizationId` | string | いいえ | マルチ組織Grafanaインスタンス用の組織ID | | `from` | number | いいえ | エポックミリ秒での開始時間 | | `to` | number | いいえ | エポックミリ秒での終了時間 | -| `dashboardUid` | string | いいえ | ダッシュボードUIDでフィルタリング | +| `dashboardUid` | string | はい | アノテーションを取得するダッシュボードのUID | | `panelId` | number | いいえ | パネルIDでフィルタリング | | `tags` | string | いいえ | フィルタリングするタグのカンマ区切りリスト | -| `type` | string | いいえ | タイプでフィルタリング(アラートまたはアノテーション) | +| `type` | string | いいえ | タイプでフィルタリング(alertまたはannotation) | | `limit` | number | いいえ | 返すアノテーションの最大数 | #### 出力 @@ -487,6 +487,16 @@ Grafanaに新しいフォルダを作成 | `uid` | string | 作成されたフォルダのUID | | `title` | string | 作成されたフォルダのタイトル | | `url` | string | フォルダへのURLパス | +| `hasAcl` | boolean | フォルダがカスタムACL権限を持っているかどうか | +| `canSave` | boolean | 現在のユーザーがフォルダを保存できるかどうか | +| `canEdit` | boolean | 現在のユーザーがフォルダを編集できるかどうか | +| `canAdmin` | boolean | 現在のユーザーがフォルダに対して管理者権限を持っているかどうか | +| `canDelete` | boolean | 現在のユーザーがフォルダを削除できるかどうか | +| `createdBy` | string | フォルダを作成したユーザーのユーザー名 | +| `created` | string | フォルダが作成されたときのタイムスタンプ | +| `updatedBy` | string | フォルダを最後に更新したユーザーのユーザー名 | +| `updated` | string | フォルダが最後に更新されたときのタイムスタンプ | +| `version` | number | フォルダのバージョン番号 | ## メモ diff --git a/apps/docs/content/docs/ja/tools/spotify.mdx b/apps/docs/content/docs/ja/tools/spotify.mdx new file mode 100644 index 0000000000..3726a2da23 --- /dev/null +++ b/apps/docs/content/docs/ja/tools/spotify.mdx @@ -0,0 +1,1452 @@ +--- +title: Spotify +description: 音楽を検索し、プレイリストを管理し、再生をコントロールし、ライブラリにアクセスする +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## 使用方法 + +Spotifyをワークフローに統合しましょう。トラック、アルバム、アーティスト、プレイリストを検索できます。プレイリストの管理、ライブラリへのアクセス、再生のコントロール、ポッドキャストやオーディオブックの閲覧ができます。 + +## ツール + +### `spotify_search` + +Spotifyでトラック、アルバム、アーティスト、またはプレイリストを検索します。クエリに基づいて一致する結果を返します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `query` | string | はい | 検索クエリ \(例: "Bohemian Rhapsody"、"artist:Queen"、"genre:rock"\) | +| `type` | string | いいえ | 結果の種類: track、album、artist、playlist、またはカンマ区切り \(例: "track,artist"\) | +| `limit` | number | いいえ | 返す結果の最大数 \(1-50\) | +| `offset` | number | いいえ | ページネーション用の最初の結果のインデックス | +| `market` | string | いいえ | 結果をフィルタリングするためのISO 3166-1 alpha-2国コード \(例: "US"、"GB"\) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | 一致するトラックのリスト | + +### `spotify_get_track` + +IDによってSpotify上の特定のトラックに関する詳細情報を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | はい | トラックのSpotify ID | +| `market` | string | いいえ | トラックの利用可能性のためのISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | Spotify トラックID | +| `name` | string | トラック名 | +| `artists` | array | アーティストのリスト | +| `album` | object | アルバム情報 | +| `duration_ms` | number | トラックの再生時間(ミリ秒) | +| `explicit` | boolean | トラックに露骨なコンテンツが含まれているかどうか | +| `popularity` | number | 人気度スコア(0-100) | +| `preview_url` | string | 30秒プレビューのURL | +| `external_url` | string | Spotify URL | +| `uri` | string | トラック用のSpotify URI | + +### `spotify_get_tracks` + +IDによって複数のSpotifyトラックに関する詳細情報を取得します(最大50件)。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | はい | カンマ区切りのSpotifyトラックIDリスト(最大50件) | +| `market` | string | いいえ | トラックの利用可能性を確認するためのISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | トラックのリスト | + +### `spotify_get_album` + +IDによってSpotifyアルバムに関する詳細情報(トラックリストを含む)を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | はい | アルバムのSpotify ID | +| `market` | string | いいえ | トラックの利用可能性を確認するためのISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | Spotify アルバム ID | +| `name` | string | アルバム名 | +| `artists` | array | アーティストのリスト | +| `album_type` | string | アルバムの種類(album、single、compilation) | +| `total_tracks` | number | トラックの総数 | +| `release_date` | string | リリース日 | +| `label` | string | レコードレーベル | +| `popularity` | number | 人気度スコア(0-100) | +| `genres` | array | ジャンルのリスト | +| `image_url` | string | アルバムカバー画像のURL | +| `tracks` | array | アルバム内のトラックリスト | +| `external_url` | string | Spotify URL | + +### `spotify_get_albums` + +複数のアルバムの詳細をIDで取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | はい | カンマ区切りのアルバムID(最大20個) | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `albums` | json | アルバムのリスト | + +### `spotify_get_album_tracks` + +アルバムからトラックを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | はい | Spotify アルバム ID | +| `limit` | number | いいえ | 返すトラック数(1-50) | +| `offset` | number | いいえ | 返す最初のトラックのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | json | トラックのリスト | +| `total` | number | トラックの総数 | +| `next` | string | 次のページのURL | + +### `spotify_get_saved_albums` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すアルバム数(1-50) | +| `offset` | number | いいえ | 返す最初のアルバムのインデックス | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `albums` | json | 保存されたアルバムのリスト | +| `total` | number | 保存されたアルバムの総数 | +| `next` | string | 次のページのURL | + +### `spotify_save_albums` + +ユーザーにアルバムを保存する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | はい | カンマ区切りのアルバムID(最大20) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | アルバムが保存されたかどうか | + +### `spotify_remove_saved_albums` + +ユーザーからアルバムを削除する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | はい | カンマ区切りのアルバムID(最大20) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | アルバムが削除されたかどうか | + +### `spotify_check_saved_albums` + +アルバムがライブラリに保存されているかを確認します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | はい | カンマ区切りのアルバムID(最大20個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各アルバムに対するブール値の配列 | + +### `spotify_get_artist` + +IDによってSpotify上のアーティストに関する詳細情報を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | はい | アーティストのSpotify ID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | SpotifyアーティストID | +| `name` | string | アーティスト名 | +| `genres` | array | アーティストに関連するジャンルのリスト | +| `popularity` | number | 人気度スコア(0-100) | +| `followers` | number | フォロワー数 | +| `image_url` | string | アーティスト画像のURL | +| `external_url` | string | Spotify URL | + +### `spotify_get_artists` + +複数のアーティストの詳細をIDで取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | はい | カンマ区切りのアーティストID(最大50個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `artists` | json | アーティストのリスト | + +### `spotify_get_artist_albums` + +Spotifyでアーティストのアルバムを取得します。アルバムタイプでフィルタリングできます。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | はい | アーティストのSpotify ID | +| `include_groups` | string | いいえ | アルバムタイプでフィルタリング: album, single, appears_on, compilation (カンマ区切り) | +| `limit` | number | いいえ | 返すアルバムの最大数(1-50) | +| `offset` | number | いいえ | 返す最初のアルバムのインデックス | +| `market` | string | いいえ | ISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `albums` | array | アーティスト | + +### `spotify_get_artist_top_tracks` + +Spotifyでアーティストの最も人気のある上位10曲を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | はい | アーティストのSpotify ID | +| `market` | string | いいえ | ISO 3166-1 alpha-2国コード(このエンドポイントでは必須) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | アーティスト | + +### `spotify_follow_artists` + +一人または複数のアーティストをフォローします。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | はい | フォローするアーティストIDをカンマ区切りで指定(最大50) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | アーティストのフォローが成功したかどうか | + +### `spotify_unfollow_artists` + +一人または複数のアーティストのフォローを解除します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | はい | フォロー解除するアーティストIDをカンマ区切りで指定(最大50) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | アーティストのフォロー解除が成功したかどうか | + +### `spotify_get_followed_artists` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すアーティストの数(1-50) | +| `after` | string | いいえ | ページネーション用カーソル(前回リクエストの最後のアーティストID) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `artists` | json | フォロー中のアーティストのリスト | +| `total` | number | フォロー中のアーティストの総数 | +| `next` | string | 次ページ用カーソル | + +### `spotify_check_following` + +ユーザーがアーティストまたは他のユーザーをフォローしているかを確認します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `type` | string | はい | 確認するタイプ:"artist"または"user" | +| `ids` | string | はい | アーティストまたはユーザーIDをカンマ区切りで指定(最大50) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各IDに対するブール値の配列 | + +### `spotify_get_show` + +ポッドキャスト番組の詳細を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showId` | string | はい | Spotify番組ID | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | 番組ID | +| `name` | string | 番組名 | +| `description` | string | 番組説明 | +| `publisher` | string | パブリッシャー名 | +| `total_episodes` | number | 総エピソード数 | +| `explicit` | boolean | 露骨なコンテンツを含むかどうか | +| `languages` | json | 言語 | +| `image_url` | string | カバー画像のURL | +| `external_url` | string | Spotify URL | + +### `spotify_get_shows` + +複数のポッドキャスト番組の詳細を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | はい | カンマ区切りの番組ID(最大50) | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `shows` | json | 番組のリスト | + +### `spotify_get_show_episodes` + +ポッドキャスト番組からエピソードを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showId` | string | はい | Spotify番組ID | +| `limit` | number | いいえ | 返すエピソード数(1-50) | +| `offset` | number | いいえ | 返す最初のエピソードのインデックス | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `episodes` | json | エピソードのリスト | +| `total` | number | 合計エピソード数 | +| `next` | string | 次のページのURL | + +### `spotify_get_saved_shows` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返す番組数(1-50) | +| `offset` | number | いいえ | 返す最初の番組のインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `shows` | json | 保存された番組のリスト | +| `total` | number | 保存された番組の合計数 | +| `next` | string | 次のページのURL | + +### `spotify_save_shows` + +ポッドキャスト番組をユーザーに保存する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | はい | カンマ区切りの番組ID(最大50) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 番組が保存されたかどうか | + +### `spotify_remove_saved_shows` + +ユーザーからポッドキャスト番組を削除する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | はい | カンマ区切りの番組ID(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 番組が削除されたかどうか | + +### `spotify_check_saved_shows` + +ライブラリに番組が保存されているかを確認する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | はい | カンマ区切りの番組ID(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各番組に対するブール値の配列 | + +### `spotify_get_episode` + +ポッドキャストエピソードの詳細を取得する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | はい | Spotify エピソードID | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | エピソードID | +| `name` | string | エピソード名 | +| `description` | string | エピソードの説明 | +| `duration_ms` | number | 再生時間(ミリ秒) | +| `release_date` | string | 公開日 | +| `explicit` | boolean | 露骨なコンテンツを含むかどうか | +| `show` | json | 親番組情報 | +| `image_url` | string | カバー画像のURL | +| `external_url` | string | Spotify URL | + +### `spotify_get_episodes` + +複数のポッドキャストエピソードの詳細を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | はい | カンマ区切りのエピソードID(最大50件) | +| `market` | string | いいえ | 市場のISOカントリーコード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `episodes` | json | エピソードのリスト | + +### `spotify_get_saved_episodes` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すエピソード数(1-50) | +| `offset` | number | いいえ | 返す最初のエピソードのインデックス | +| `market` | string | いいえ | 市場のISOカントリーコード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `episodes` | json | 保存されたエピソードのリスト | +| `total` | number | 保存されたエピソードの総数 | +| `next` | string | 次のページのURL | + +### `spotify_save_episodes` + +ポッドキャストエピソードをユーザーに保存する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | はい | カンマ区切りのエピソードID(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | エピソードが保存されたかどうか | + +### `spotify_remove_saved_episodes` + +ユーザーからポッドキャストエピソードを削除する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | はい | カンマ区切りのエピソードID(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | エピソードが削除されたかどうか | + +### `spotify_check_saved_episodes` + +エピソードがライブラリに保存されているかを確認する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | はい | カンマ区切りのエピソードID(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各エピソードに対するブール値の配列 | + +### `spotify_get_audiobook` + +オーディオブックの詳細を取得する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | はい | Spotifyオーディオブック ID | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | オーディオブックID | +| `name` | string | オーディオブック名 | +| `authors` | json | 著者 | +| `narrators` | json | ナレーター | +| `publisher` | string | 出版社 | +| `description` | string | 説明 | +| `total_chapters` | number | 総チャプター数 | +| `languages` | json | 言語 | +| `image_url` | string | カバー画像URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_audiobooks` + +複数のオーディオブックの詳細を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | はい | カンマ区切りのオーディオブックID(最大50個) | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `audiobooks` | json | オーディオブックのリスト | + +### `spotify_get_audiobook_chapters` + +オーディオブックからチャプターを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | はい | SpotifyオーディオブックID | +| `limit` | number | いいえ | 返すチャプターの数(1-50) | +| `offset` | number | いいえ | 返す最初のチャプターのインデックス | +| `market` | string | いいえ | マーケット用のISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `chapters` | json | チャプターのリスト | +| `total` | number | チャプターの総数 | +| `next` | string | 次のページのURL | + +### `spotify_get_saved_audiobooks` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すオーディオブックの数(1-50) | +| `offset` | number | いいえ | 返す最初のオーディオブックのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `audiobooks` | json | 保存されたオーディオブックのリスト | +| `total` | number | 保存されたオーディオブックの合計数 | +| `next` | string | 次のページのURL | + +### `spotify_save_audiobooks` + +ユーザーにオーディオブックを保存する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | はい | カンマ区切りのオーディオブックID(最大50個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | オーディオブックが保存されたかどうか | + +### `spotify_remove_saved_audiobooks` + +ユーザーからオーディオブックを削除する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | はい | カンマ区切りのオーディオブックID(最大50個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | オーディオブックが削除されたかどうか | + +### `spotify_check_saved_audiobooks` + +オーディオブックがライブラリに保存されているかを確認する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | はい | カンマ区切りのオーディオブックID(最大50個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各オーディオブックに対するブール値の配列 | + +### `spotify_get_playlist` + +IDによってSpotifyのプレイリストに関する詳細情報を取得する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | プレイリストのSpotify ID | +| `market` | string | いいえ | トラックの利用可能性を確認するためのISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | SpotifyプレイリストID | +| `name` | string | プレイリスト名 | +| `description` | string | プレイリストの説明 | +| `public` | boolean | プレイリストが公開されているかどうか | +| `collaborative` | boolean | プレイリストがコラボレーティブかどうか | +| `owner` | object | プレイリスト所有者の情報 | +| `image_url` | string | プレイリストのカバー画像URL | +| `total_tracks` | number | トラックの総数 | +| `snapshot_id` | string | バージョン管理用のプレイリストスナップショットID | +| `external_url` | string | Spotify URL | + +### `spotify_get_playlist_tracks` + +Spotifyプレイリスト内のトラックを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | プレイリストのSpotify ID | +| `limit` | number | いいえ | 返すトラックの最大数(1-100) | +| `offset` | number | いいえ | 返す最初のトラックのインデックス | +| `market` | string | いいえ | トラックの利用可能性を確認するためのISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | プレイリスト内のトラックのリスト | + +### `spotify_get_playlist_cover` + +プレイリストを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリスト ID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `images` | json | カバー画像のリスト | + +### `spotify_get_user_playlists` + +現在のユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すプレイリストの最大数(1-50) | +| `offset` | number | いいえ | 返す最初のプレイリストのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `playlists` | array | ユーザー | + +### `spotify_create_playlist` + +現在のユーザー用に Spotify で新しいプレイリストを作成する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `name` | string | はい | 新しいプレイリストの名前 | +| `description` | string | いいえ | プレイリストの説明 | +| `public` | boolean | いいえ | プレイリストを公開するかどうか | +| `collaborative` | boolean | いいえ | プレイリストをコラボレーティブにするかどうか(public を false にする必要があります) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | Spotify プレイリスト ID | +| `name` | string | プレイリスト名 | +| `description` | string | プレイリストの説明 | +| `public` | boolean | プレイリストが公開されているかどうか | +| `collaborative` | boolean | コラボレーション可能かどうか | +| `snapshot_id` | string | プレイリストのスナップショット ID | +| `external_url` | string | Spotify URL | + +### `spotify_update_playlist` + +プレイリストを更新する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリスト ID | +| `name` | string | いいえ | プレイリストの新しい名前 | +| `description` | string | いいえ | プレイリストの新しい説明 | +| `public` | boolean | いいえ | プレイリストを公開するかどうか | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 更新が成功したかどうか | + +### `spotify_add_playlist_cover` + +プレイリスト用のカスタムカバー画像をアップロードします。画像はJPEG形式で256KB未満である必要があります。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリスト ID | +| `imageBase64` | string | はい | Base64エンコードされたJPEG画像(最大256KB) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | アップロードが成功したかどうか | + +### `spotify_add_tracks_to_playlist` + +Spotifyプレイリストに1つ以上のトラックを追加します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | プレイリストのSpotify ID | +| `uris` | string | はい | カンマ区切りのSpotify URI(例:"spotify:track:xxx,spotify:track:yyy") | +| `position` | number | いいえ | トラックを挿入する位置(0ベース)。省略した場合、トラックは末尾に追加されます。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 変更後の新しいプレイリストスナップショットID | + +### `spotify_remove_tracks_from_playlist` + +Spotifyプレイリストから1つ以上のトラックを削除します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | プレイリストのSpotify ID | +| `uris` | string | はい | 削除するカンマ区切りのSpotify URI(例:"spotify:track:xxx,spotify:track:yyy") | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 変更後の新しいプレイリストスナップショットID | + +### `spotify_reorder_playlist_items` + +プレイリスト内のトラックを別の位置に移動します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | SpotifyプレイリストID | +| `range_start` | number | はい | 並べ替えるアイテムの開始インデックス | +| `insert_before` | number | はい | アイテムを挿入する前のインデックス | +| `range_length` | number | いいえ | 並べ替えるアイテムの数 | +| `snapshot_id` | string | いいえ | 同時実行制御用のプレイリストスナップショットID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 新しいプレイリストのスナップショットID | + +### `spotify_replace_playlist_items` + +プレイリスト内のすべての項目を新しいトラックに置き換えます。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリストID | +| `uris` | string | はい | カンマ区切りの Spotify URI(最大100個) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 新しいプレイリストのスナップショットID | + +### `spotify_follow_playlist` + +プレイリストをフォロー(保存)します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリストID | +| `public` | boolean | いいえ | プレイリストを公開プレイリストに含めるかどうか | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | フォローが成功したかどうか | + +### `spotify_unfollow_playlist` + +プレイリストのフォローを解除(保存解除)します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリストID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | フォロー解除が成功したかどうか | + +### `spotify_check_playlist_followers` + +ユーザーがプレイリストをフォローしているかを確認します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | はい | Spotify プレイリスト ID | +| `userIds` | string | はい | 確認するユーザー ID(カンマ区切り、最大5件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 各ユーザーに対するブール値の配列 | + +### `spotify_get_current_user` + +現在のユーザーを取得 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | Spotify ユーザー ID | +| `display_name` | string | 表示名 | +| `email` | string | メールアドレス | +| `country` | string | 国コード | +| `product` | string | サブスクリプションレベル(無料、プレミアム) | +| `followers` | number | フォロワー数 | +| `image_url` | string | プロフィール画像 URL | +| `external_url` | string | Spotify プロフィール URL | + +### `spotify_get_user_profile` + +ユーザーを取得 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `userId` | string | はい | Spotify ユーザー ID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `id` | string | ユーザー ID | +| `display_name` | string | 表示名 | +| `followers` | number | フォロワー数 | +| `image_url` | string | プロフィール画像 URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_top_tracks` + +現在のユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | いいえ | 時間範囲:short_term(約4週間)、medium_term(約6ヶ月)、long_term(数年) | +| `limit` | number | いいえ | 返すトラック数(1-50) | +| `offset` | number | いいえ | 返す最初のトラックのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | ユーザー | + +### `spotify_get_top_artists` + +現在のユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | いいえ | 時間範囲:short_term(約4週間)、medium_term(約6ヶ月)、long_term(数年) | +| `limit` | number | いいえ | 返すアーティスト数(1-50) | +| `offset` | number | いいえ | 返す最初のアーティストのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `artists` | array | ユーザー | + +### `spotify_get_saved_tracks` + +現在のユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すトラック数(1-50) | +| `offset` | number | いいえ | 返す最初のトラックのインデックス | +| `market` | string | いいえ | ISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `tracks` | array | ユーザー | + +### `spotify_save_tracks` + +現在のユーザーにトラックを保存する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | はい | 保存するSpotifyトラックIDをカンマ区切りで指定(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | トラックが正常に保存されたかどうか | + +### `spotify_remove_saved_tracks` + +ユーザーからトラックを削除する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | はい | 削除するトラックIDをカンマ区切りで指定(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | トラックが正常に削除されたかどうか | + +### `spotify_check_saved_tracks` + +1つ以上のトラックがユーザーに保存されているかを確認する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | はい | 確認するトラックIDをカンマ区切りで指定(最大50件) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `results` | json | 保存状態を含むトラックIDの配列 | +| `all_saved` | boolean | すべてのトラックが保存されているかどうか | +| `none_saved` | boolean | トラックが1つも保存されていないかどうか | + +### `spotify_get_recently_played` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | いいえ | 返すトラック数(1-50) | +| `after` | number | いいえ | ミリ秒単位のUnixタイムスタンプ。このカーソル以降のアイテムを返します。 | +| `before` | number | いいえ | ミリ秒単位のUnixタイムスタンプ。このカーソル以前のアイテムを返します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `items` | array | 最近再生したトラック | + +### `spotify_get_new_releases` + +Spotifyで紹介されている新しいアルバムリリースのリストを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `country` | string | いいえ | ISO 3166-1 alpha-2国コード(例:"US"、"GB") | +| `limit` | number | いいえ | 返すリリース数(1-50) | +| `offset` | number | いいえ | 返す最初のリリースのインデックス | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `albums` | json | 新しいリリースのリスト | +| `total` | number | 新しいリリースの総数 | +| `next` | string | 次のページのURL | + +### `spotify_get_categories` + +Spotifyでアイテムにタグ付けするために使用されるブラウズカテゴリのリストを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `country` | string | いいえ | ISO 3166-1 alpha-2国コード(例:"US"、"GB") | +| `locale` | string | いいえ | ロケールコード(例:"en_US"、"es_MX") | +| `limit` | number | いいえ | 返すカテゴリ数(1-50) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `categories` | json | ブラウズカテゴリのリスト | +| `total` | number | カテゴリの総数 | + +### `spotify_get_markets` + +Spotifyが利用可能な市場のリストを取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `markets` | json | ISO国コードのリスト | + +### `spotify_get_playback_state` + +デバイス、トラック、進行状況を含む現在の再生状態を取得します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `market` | string | いいえ | ISO 3166-1 alpha-2国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `is_playing` | boolean | 再生がアクティブかどうか | +| `device` | object | アクティブなデバイス情報 | +| `progress_ms` | number | ミリ秒単位の進行状況 | +| `currently_playing_type` | string | 再生中のコンテンツの種類 | +| `shuffle_state` | boolean | シャッフルが有効かどうか | +| `repeat_state` | string | リピートモード(off、track、context) | +| `track` | object | 現在再生中のトラック | + +### `spotify_get_currently_playing` + +ユーザーを取得する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `market` | string | いいえ | 市場のためのISO国コード | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `is_playing` | boolean | 再生がアクティブかどうか | +| `progress_ms` | number | トラック内の現在位置(ミリ秒) | +| `track` | json | 現在再生中のトラック | + +### `spotify_get_devices` + +ユーザーを取得 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `devices` | array | 利用可能な再生デバイス | + +### `spotify_get_queue` + +ユーザーを取得 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `currently_playing` | json | 現在再生中のトラック | +| `queue` | json | キュー内の次のトラック | + +### `spotify_play` + +Spotifyで再生を開始または再開します。特定のトラック、アルバム、またはプレイリストを再生できます。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | いいえ | 再生するデバイスID。提供されない場合、アクティブなデバイスで再生します。 | +| `context_uri` | string | いいえ | 再生するアルバム、アーティスト、またはプレイリストのSpotify URI(例:"spotify:album:xxx") | +| `uris` | string | いいえ | 再生するトラックURIのカンマ区切りリスト(例:"spotify:track:xxx,spotify:track:yyy") | +| `offset` | number | いいえ | 再生を開始するコンテキスト内の位置(0ベースのインデックス) | +| `position_ms` | number | いいえ | トラック内の開始位置(ミリ秒単位) | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 再生が正常に開始されたかどうか | + +### `spotify_pause` + +Spotifyでの再生を一時停止します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | いいえ | 一時停止するデバイスID。提供されない場合、アクティブなデバイスを一時停止します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 再生が一時停止されたかどうか | + +### `spotify_skip_next` + +Spotifyで次のトラックにスキップします。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | いいえ | デバイスID。提供されない場合、アクティブなデバイスを使用します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | スキップが成功したかどうか | + +### `spotify_skip_previous` + +Spotifyで前のトラックにスキップします。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | いいえ | デバイスID。提供されない場合、アクティブなデバイスを使用します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | スキップが成功したかどうか | + +### `spotify_seek` + +現在再生中のトラックの特定の位置にシークします。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `position_ms` | number | はい | シークする位置(ミリ秒) | +| `device_id` | string | いいえ | 対象デバイスID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | シークが成功したかどうか | + +### `spotify_add_to_queue` + +ユーザーにトラックを追加する + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `uri` | string | はい | 追加するトラックのSpotify URI(例:"spotify:track:xxx") | +| `device_id` | string | いいえ | デバイスID。提供されない場合、アクティブなデバイスを使用します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | トラックがキューに追加されたかどうか | + +### `spotify_set_volume` + +Spotifyの再生音量を設定する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `volume_percent` | number | はい | 音量レベル(0〜100) | +| `device_id` | string | いいえ | デバイスID。提供されない場合、アクティブなデバイスを使用します。 | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 音量が設定されたかどうか | + +### `spotify_set_repeat` + +再生のリピートモードを設定する。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `state` | string | はい | リピートモード: "off"、"track"、または "context" | +| `device_id` | string | いいえ | 対象とするデバイスID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | リピートモードが正常に設定されたかどうか | + +### `spotify_set_shuffle` + +シャッフルのオン・オフを切り替えます。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `state` | boolean | はい | シャッフルをオンにする場合はtrue、オフにする場合はfalse | +| `device_id` | string | いいえ | 対象とするデバイスID | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | シャッフルが正常に設定されたかどうか | + +### `spotify_transfer_playback` + +再生を別のデバイスに転送します。 + +#### 入力 + +| パラメータ | 型 | 必須 | 説明 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | はい | 再生を転送する先のデバイスID | +| `play` | boolean | いいえ | 新しいデバイスで再生を開始するかどうか | + +#### 出力 + +| パラメータ | 型 | 説明 | +| --------- | ---- | ----------- | +| `success` | boolean | 転送が成功したかどうか | + +## 注意事項 + +- カテゴリー: `tools` +- タイプ: `spotify` diff --git a/apps/docs/content/docs/ja/tools/zep.mdx b/apps/docs/content/docs/ja/tools/zep.mdx index 1502da166f..e4c478190a 100644 --- a/apps/docs/content/docs/ja/tools/zep.mdx +++ b/apps/docs/content/docs/ja/tools/zep.mdx @@ -94,10 +94,7 @@ Zepから会話スレッドを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `context` | string | コンテキスト文字列(サマリーまたは基本) | -| `facts` | array | 抽出されたファクト | -| `entities` | array | 抽出されたエンティティ | -| `summary` | string | 会話のサマリー | +| `context` | string | コンテキスト文字列(要約または基本モード) | ### `zep_get_messages` @@ -137,9 +134,9 @@ Zepから会話スレッドを削除する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | -| `context` | string | メッセージ追加後の更新されたコンテキスト | -| `messageIds` | array | 追加されたメッセージUUIDの配列 | | `threadId` | string | スレッドID | +| `added` | boolean | メッセージが正常に追加されたかどうか | +| `messageIds` | array | 追加されたメッセージUUIDの配列 | ### `zep_add_user` @@ -209,7 +206,7 @@ Zepからユーザー情報を取得する | パラメータ | 型 | 説明 | | --------- | ---- | ----------- | | `threads` | array | このユーザーのスレッドオブジェクトの配列 | -| `userId` | string | ユーザーID | +| `totalCount` | number | 返されたスレッドの総数 | ## 注意事項 diff --git a/apps/docs/content/docs/zh/tools/grafana.mdx b/apps/docs/content/docs/zh/tools/grafana.mdx index ada49f5480..530e26109b 100644 --- a/apps/docs/content/docs/zh/tools/grafana.mdx +++ b/apps/docs/content/docs/zh/tools/grafana.mdx @@ -320,11 +320,11 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | `baseUrl` | string | 是 | Grafana 实例 URL \(例如:https://your-grafana.com\) | | `organizationId` | string | 否 | 多组织 Grafana 实例的组织 ID | | `text` | string | 是 | 注释的文本内容 | -| `tags` | string | 否 | 以逗号分隔的标签列表 | -| `dashboardUid` | string | 否 | 要添加注释的仪表板 UID \(全局注释可选\) | +| `tags` | string | 否 | 逗号分隔的标签列表 | +| `dashboardUid` | string | 是 | 要添加注释的仪表板 UID | | `panelId` | number | 否 | 要添加注释的面板 ID | -| `time` | number | 否 | 起始时间(以 epoch 毫秒为单位,默认为当前时间) | -| `timeEnd` | number | 否 | 结束时间(以 epoch 毫秒为单位,用于范围注释) | +| `time` | number | 否 | 开始时间(以纪元毫秒为单位,默认为当前时间) | +| `timeEnd` | number | 否 | 结束时间(以纪元毫秒为单位,用于范围注释) | #### 输出 @@ -342,15 +342,15 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 必需 | 描述 | | --------- | ---- | -------- | ----------- | | `apiKey` | string | 是 | Grafana 服务账户令牌 | -| ---INLINE-CODE-PLACEHOLDER-42355e89d407292dbef683bcc5a4fc3e--- | string | 是 | Grafana 实例 URL \(例如:https://your-grafana.com\) | +| `baseUrl` | string | 是 | Grafana 实例 URL \(例如:https://your-grafana.com\) | | `organizationId` | string | 否 | 多组织 Grafana 实例的组织 ID | -| `from` | number | 否 | 起始时间(以 epoch 毫秒为单位) | -| `to` | number | 否 | 结束时间(以 epoch 毫秒为单位) | -| `dashboardUid` | string | 否 | 按仪表板 UID 过滤 | +| `from` | number | 否 | 开始时间(以纪元毫秒为单位) | +| `to` | number | 否 | 结束时间(以纪元毫秒为单位) | +| `dashboardUid` | string | 是 | 要查询注释的仪表板 UID | | `panelId` | number | 否 | 按面板 ID 过滤 | -| `tags` | string | 否 | 按逗号分隔的标签列表过滤 | -| `type` | string | 否 | 按类型过滤 \(警报或注释\) | -| `limit` | number | 否 | 返回的最大注释数 | +| `tags` | string | 否 | 按标签过滤(逗号分隔) | +| `type` | string | 否 | 按类型过滤 \(alert 或 annotation\) | +| `limit` | number | 否 | 返回的注释最大数量 | #### 输出 @@ -483,10 +483,20 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `id` | number | 创建的文件夹的数字 ID | -| `uid` | string | 创建的文件夹的 UID | -| `title` | string | 创建的文件夹的标题 | +| `id` | number | 创建文件夹的数字 ID | +| `uid` | string | 创建文件夹的 UID | +| `title` | string | 创建文件夹的标题 | | `url` | string | 文件夹的 URL 路径 | +| `hasAcl` | boolean | 文件夹是否具有自定义 ACL 权限 | +| `canSave` | boolean | 当前用户是否可以保存文件夹 | +| `canEdit` | boolean | 当前用户是否可以编辑文件夹 | +| `canAdmin` | boolean | 当前用户是否对文件夹具有管理员权限 | +| `canDelete` | boolean | 当前用户是否可以删除文件夹 | +| `createdBy` | string | 创建文件夹的用户名 | +| `created` | string | 文件夹创建的时间戳 | +| `updatedBy` | string | 最后更新文件夹的用户名 | +| `updated` | string | 文件夹最后更新的时间戳 | +| `version` | number | 文件夹的版本号 | ## 注意事项 diff --git a/apps/docs/content/docs/zh/tools/spotify.mdx b/apps/docs/content/docs/zh/tools/spotify.mdx new file mode 100644 index 0000000000..7f03b0bdeb --- /dev/null +++ b/apps/docs/content/docs/zh/tools/spotify.mdx @@ -0,0 +1,1452 @@ +--- +title: Spotify +description: 搜索音乐、管理播放列表、控制播放并访问您的音乐库 +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## 使用说明 + +将 Spotify 集成到您的工作流程中。搜索曲目、专辑、艺术家和播放列表。管理播放列表,访问您的音乐库,控制播放,浏览播客和有声书。 + +## 工具 + +### `spotify_search` + +在 Spotify 上搜索曲目、专辑、艺术家或播放列表。根据查询返回匹配的结果。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `query` | string | 是 | 搜索查询 \(例如:"Bohemian Rhapsody", "artist:Queen", "genre:rock"\) | +| `type` | string | 否 | 结果类型:track, album, artist, playlist 或逗号分隔 \(例如:"track,artist"\) | +| `limit` | number | 否 | 返回结果的最大数量 \(1-50\) | +| `offset` | number | 否 | 分页时返回的第一个结果的索引 | +| `market` | string | 否 | 用于过滤结果的 ISO 3166-1 alpha-2 国家代码 \(例如:"US", "GB"\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 匹配曲目的列表 | + +### `spotify_get_track` + +通过其 ID 获取 Spotify 上特定曲目的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `trackId` | string | 是 | 曲目的 Spotify ID | +| `market` | string | 否 | 曲目可用性的 ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | Spotify 曲目 ID | +| `name` | string | 曲目名称 | +| `artists` | array | 艺术家列表 | +| `album` | object | 专辑信息 | +| `duration_ms` | number | 曲目时长(毫秒) | +| `explicit` | boolean | 曲目是否包含显式内容 | +| `popularity` | number | 热度评分 \(0-100\) | +| `preview_url` | string | 30 秒预览的 URL | +| `external_url` | string | Spotify URL | +| `uri` | string | 曲目的 Spotify URI | + +### `spotify_get_tracks` + +通过曲目 ID(最多 50 个)获取 Spotify 上多个曲目的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | 是 | 逗号分隔的 Spotify 曲目 ID 列表 \(最多 50 个\) | +| `market` | string | 否 | 曲目可用性的 ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 曲目列表 | + +### `spotify_get_album` + +通过专辑 ID 获取 Spotify 上专辑的详细信息,包括曲目列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | 是 | 专辑的 Spotify ID | +| `market` | string | 否 | 曲目可用性的 ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | Spotify 专辑 ID | +| `name` | string | 专辑名称 | +| `artists` | array | 艺术家列表 | +| `album_type` | string | 专辑类型 \(专辑、单曲、合辑\) | +| `total_tracks` | number | 曲目总数 | +| `release_date` | string | 发行日期 | +| `label` | string | 唱片公司 | +| `popularity` | number | 热度评分 \(0-100\) | +| `genres` | array | 流派列表 | +| `image_url` | string | 专辑封面图片 URL | +| `tracks` | array | 专辑中的曲目列表 | +| `external_url` | string | Spotify URL | + +### `spotify_get_albums` + +通过专辑 ID 获取多个专辑的详细信息。 + +#### 输入 + +| 参数 | 类型 | 是否必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | 是 | 逗号分隔的专辑 ID \(最多 20 个\) | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `albums` | json | 专辑列表 | + +### `spotify_get_album_tracks` + +获取专辑中的曲目。 + +#### 输入 + +| 参数 | 类型 | 是否必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumId` | string | 是 | Spotify 专辑 ID | +| `limit` | number | 否 | 返回的曲目数量 \(1-50\) | +| `offset` | number | 否 | 返回的首个曲目的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | json | 曲目列表 | +| `total` | number | 曲目总数 | +| `next` | string | 下一页的 URL | + +### `spotify_get_saved_albums` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 要返回的专辑数量 \(1-50\) | +| `offset` | number | 否 | 要返回的第一个专辑的索引 | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `albums` | json | 已保存专辑列表 | +| `total` | number | 已保存专辑总数 | +| `next` | string | 下一页的 URL | + +### `spotify_save_albums` + +将专辑保存到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | 是 | 逗号分隔的专辑 ID \(最多 20 个\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否已保存专辑 | + +### `spotify_remove_saved_albums` + +从用户中移除专辑 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | string | 是 | 逗号分隔的专辑 ID \(最多 20 个\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | 布尔值 | 是否移除了专辑 | + +### `spotify_check_saved_albums` + +检查专辑是否已保存到库中。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `albumIds` | 字符串 | 是 | 逗号分隔的专辑 ID(最多 20 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | JSON | 每个专辑的布尔值数组 | + +### `spotify_get_artist` + +通过 Spotify ID 获取艺术家的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistId` | 字符串 | 是 | 艺术家的 Spotify ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | 字符串 | Spotify 艺术家 ID | +| `name` | 字符串 | 艺术家名称 | +| `genres` | 数组 | 与艺术家相关的流派列表 | +| `popularity` | 数字 | 人气评分(0-100) | +| `followers` | 数字 | 关注者数量 | +| `image_url` | 字符串 | 艺术家图片 URL | +| `external_url` | 字符串 | Spotify URL | + +### `spotify_get_artists` + +通过 ID 获取多个艺术家的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | 字符串 | 是 | 逗号分隔的艺术家 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `artists` | json | 艺术家列表 | + +### `spotify_get_artist_albums` + +获取 Spotify 上某艺术家的专辑。可以按专辑类型筛选。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | 是 | 艺术家的 Spotify ID | +| `include_groups` | string | 否 | 按专辑类型筛选:album, single, appears_on, compilation(逗号分隔) | +| `limit` | number | 否 | 返回的专辑最大数量(1-50) | +| `offset` | number | 否 | 返回的第一个专辑的索引 | +| `market` | string | 否 | ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `albums` | array | 艺术家 | + +### `spotify_get_artist_top_tracks` + +获取 Spotify 上某艺术家的前 10 首最受欢迎的曲目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistId` | string | 是 | 艺术家的 Spotify ID | +| `market` | string | 否 | ISO 3166-1 alpha-2 国家代码(此端点必需) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 艺术家 | + +### `spotify_follow_artists` + +关注一个或多个艺术家。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | 是 | 逗号分隔的艺术家 ID 列表(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 艺术家是否成功关注 | + +### `spotify_unfollow_artists` + +取消关注一个或多个艺术家。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `artistIds` | string | 是 | 逗号分隔的艺术家 ID 列表(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 艺术家是否成功取消关注 | + +### `spotify_get_followed_artists` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 返回的艺术家数量(1-50) | +| `after` | string | 否 | 分页游标(上次请求的最后一个艺术家 ID) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `artists` | json | 已关注艺术家列表 | +| `total` | number | 已关注艺术家的总数 | +| `next` | string | 下一页的游标 | + +### `spotify_check_following` + +检查用户是否关注艺术家或用户。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `type` | string | 是 | 检查的类型:“artist” 或 “user” | +| `ids` | string | 是 | 逗号分隔的艺术家或用户 ID 列表(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 每个 ID 的布尔值数组 | + +### `spotify_get_show` + +获取播客节目的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showId` | string | 是 | Spotify 节目 ID | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | 节目 ID | +| `name` | string | 节目名称 | +| `description` | string | 节目描述 | +| `publisher` | string | 发布者名称 | +| `total_episodes` | number | 总集数 | +| `explicit` | boolean | 是否包含显式内容 | +| `languages` | json | 语言 | +| `image_url` | string | 封面图片 URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_shows` + +获取多个播客节目的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | 是 | 逗号分隔的节目 ID(最多 50 个) | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `shows` | json | 节目列表 | + +### `spotify_get_show_episodes` + +从播客节目中获取剧集。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showId` | string | 是 | Spotify 节目 ID | +| `limit` | number | 否 | 要返回的剧集数量 \(1-50\) | +| `offset` | number | 否 | 要返回的第一个剧集的索引 | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `episodes` | json | 剧集列表 | +| `total` | number | 剧集总数 | +| `next` | string | 下一页的 URL | + +### `spotify_get_saved_shows` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 要返回的节目数量 \(1-50\) | +| `offset` | number | 否 | 要返回的第一个节目的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `shows` | json | 已保存节目的列表 | +| `total` | number | 已保存节目的总数 | +| `next` | string | 下一页的 URL | + +### `spotify_save_shows` + +将播客节目保存到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | 是 | 逗号分隔的节目 ID \(最多 50 个\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否保存了节目 | + +### `spotify_remove_saved_shows` + +从用户中移除播客节目 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | 是 | 逗号分隔的节目 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否移除了节目 | + +### `spotify_check_saved_shows` + +检查节目是否已保存在库中。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `showIds` | string | 是 | 逗号分隔的节目 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 每个节目的布尔值数组 | + +### `spotify_get_episode` + +获取播客剧集的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `episodeId` | string | 是 | Spotify 剧集 ID | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | 剧集 ID | +| `name` | string | 剧集名称 | +| `description` | string | 剧集描述 | +| `duration_ms` | number | 时长(毫秒) | +| `release_date` | string | 发布日期 | +| `explicit` | boolean | 是否包含显式内容 | +| `show` | json | 父节目信息 | +| `image_url` | string | 封面图片 URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_episodes` + +获取多个播客剧集的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | 是 | 逗号分隔的剧集 ID(最多 50 个) | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `episodes` | json | 剧集列表 | + +### `spotify_get_saved_episodes` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 要返回的剧集数量(1-50) | +| `offset` | number | 否 | 要返回的第一个剧集的索引 | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `episodes` | json | 已保存的剧集列表 | +| `total` | number | 已保存剧集总数 | +| `next` | string | 下一页的 URL | + +### `spotify_save_episodes` + +将播客剧集保存到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | 是 | 逗号分隔的剧集 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 剧集是否已保存 | + +### `spotify_remove_saved_episodes` + +从用户中移除播客剧集 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | 是 | 逗号分隔的剧集 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否已移除剧集 | + +### `spotify_check_saved_episodes` + +检查剧集是否已保存到库中。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `episodeIds` | string | 是 | 逗号分隔的剧集 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 每个剧集的布尔值数组 | + +### `spotify_get_audiobook` + +获取有声书的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | 是 | Spotify 有声书 ID | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | 有声书 ID | +| `name` | string | 有声书名称 | +| `authors` | json | 作者 | +| `narrators` | json | 旁白 | +| `publisher` | string | 出版商 | +| `description` | string | 描述 | +| `total_chapters` | number | 总章节数 | +| `languages` | json | 语言 | +| `image_url` | string | 封面图片 URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_audiobooks` + +获取多个有声书的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | 是 | 逗号分隔的有声书 ID(最多 50 个) | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `audiobooks` | json | 有声书列表 | + +### `spotify_get_audiobook_chapters` + +获取有声书的章节。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookId` | string | 是 | Spotify 有声书 ID | +| `limit` | number | 否 | 返回的章节数量(1-50) | +| `offset` | number | 否 | 返回的第一个章节的索引 | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `chapters` | json | 章节列表 | +| `total` | number | 总章节数 | +| `next` | string | 下一页的 URL | + +### `spotify_get_saved_audiobooks` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 返回的有声书数量(1-50) | +| `offset` | number | 否 | 返回的第一个有声书的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `audiobooks` | json | 已保存有声书的列表 | +| `total` | number | 已保存有声书的总数 | +| `next` | string | 下一页的 URL | + +### `spotify_save_audiobooks` + +将有声书保存到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | 是 | 逗号分隔的有声书 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否已保存有声书 | + +### `spotify_remove_saved_audiobooks` + +从用户中移除有声书 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | 是 | 逗号分隔的有声书 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否已移除有声书 | + +### `spotify_check_saved_audiobooks` + +检查有声书是否已保存到库中。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `audiobookIds` | string | 是 | 逗号分隔的有声书 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 每本有声书的布尔值数组 | + +### `spotify_get_playlist` + +通过其 ID 获取 Spotify 上播放列表的详细信息。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | 播放列表的 Spotify ID | +| `market` | string | 否 | 用于曲目可用性的 ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | Spotify 播放列表 ID | +| `name` | string | 播放列表名称 | +| `description` | string | 播放列表描述 | +| `public` | boolean | 播放列表是否公开 | +| `collaborative` | boolean | 播放列表是否为协作 | +| `owner` | object | 播放列表所有者信息 | +| `image_url` | string | 播放列表封面图片 URL | +| `total_tracks` | number | 曲目总数 | +| `snapshot_id` | string | 用于版本控制的播放列表快照 ID | +| `external_url` | string | Spotify URL | + +### `spotify_get_playlist_tracks` + +获取 Spotify 播放列表中的曲目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | 播放列表的 Spotify ID | +| `limit` | number | 否 | 返回的曲目最大数量 \(1-100\) | +| `offset` | number | 否 | 返回的第一个曲目的索引 | +| `market` | string | 否 | 用于曲目可用性的 ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 播放列表中的曲目列表 | + +### `spotify_get_playlist_cover` + +获取播放列表 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `images` | json | 封面图片列表 | + +### `spotify_get_user_playlists` + +获取当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 要返回的最大播放列表数量 \(1-50\) | +| `offset` | number | 否 | 要返回的第一个播放列表的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `playlists` | array | 用户 | + +### `spotify_create_playlist` + +为当前用户在 Spotify 上创建一个新播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `name` | string | 是 | 新播放列表的名称 | +| `description` | string | 否 | 播放列表的描述 | +| `public` | boolean | 否 | 播放列表是否应为公开 | +| `collaborative` | boolean | 否 | 播放列表是否应为协作 \(需要公开设置为 false\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | Spotify 播放列表 ID | +| `name` | string | 播放列表名称 | +| `description` | string | 播放列表描述 | +| `public` | boolean | 播放列表是否公开 | +| `collaborative` | boolean | 是否可协作 | +| `snapshot_id` | string | 播放列表快照 ID | +| `external_url` | string | Spotify URL | + +### `spotify_update_playlist` + +更新播放列表 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `name` | string | 否 | 播放列表的新名称 | +| `description` | string | 否 | 播放列表的新描述 | +| `public` | boolean | 否 | 播放列表是否应公开 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 更新是否成功 | + +### `spotify_add_playlist_cover` + +为播放列表上传自定义封面图片。图片必须为 JPEG 格式且小于 256KB。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `imageBase64` | string | 是 | Base64 编码的 JPEG 图片(最大 256KB) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 上传是否成功 | + +### `spotify_add_tracks_to_playlist` + +将一首或多首曲目添加到 Spotify 播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | 播放列表的 Spotify ID | +| `uris` | string | 是 | 逗号分隔的 Spotify URI \(例如:"spotify:track:xxx,spotify:track:yyy"\) | +| `position` | number | 否 | 插入曲目的位置 \(从 0 开始\)。如果省略,曲目将追加到末尾。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 修改后新的播放列表快照 ID | + +### `spotify_remove_tracks_from_playlist` + +从 Spotify 播放列表中移除一首或多首曲目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | 播放列表的 Spotify ID | +| `uris` | string | 是 | 要移除的逗号分隔的 Spotify URI \(例如:"spotify:track:xxx,spotify:track:yyy"\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 修改后新的播放列表快照 ID | + +### `spotify_reorder_playlist_items` + +将曲目移动到播放列表中的不同位置。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `range_start` | number | 是 | 要重新排序的项目的起始索引 | +| `insert_before` | number | 是 | 插入项目之前的索引 | +| `range_length` | number | 否 | 要重新排序的项目数量 | +| `snapshot_id` | string | 否 | 用于并发控制的播放列表快照 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 新的播放列表快照 ID | + +### `spotify_replace_playlist_items` + +用新曲目替换播放列表中的所有项目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `uris` | string | 是 | 逗号分隔的 Spotify URI(最多 100 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `snapshot_id` | string | 新的播放列表快照 ID | + +### `spotify_follow_playlist` + +关注(保存)播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `public` | boolean | 否 | 播放列表是否会出现在公开播放列表中 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否关注成功 | + +### `spotify_unfollow_playlist` + +取消关注(取消保存)播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否取消关注成功 | + +### `spotify_check_playlist_followers` + +检查用户是否关注某个播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `playlistId` | string | 是 | Spotify 播放列表 ID | +| `userIds` | string | 是 | 逗号分隔的用户 ID(最多 5 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 每个用户的布尔值数组 | + +### `spotify_get_current_user` + +获取当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | Spotify 用户 ID | +| `display_name` | string | 显示名称 | +| `email` | string | 电子邮件地址 | +| `country` | string | 国家代码 | +| `product` | string | 订阅级别(免费,付费)| +| `followers` | number | 关注者数量 | +| `image_url` | string | 个人资料图片 URL | +| `external_url` | string | Spotify 个人资料 URL | + +### `spotify_get_user_profile` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `userId` | string | 是 | Spotify 用户 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `id` | string | 用户 ID | +| `display_name` | string | 显示名称 | +| `followers` | number | 关注者数量 | +| `image_url` | string | 个人资料图片 URL | +| `external_url` | string | Spotify URL | + +### `spotify_get_top_tracks` + +获取当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | 否 | 时间范围:short_term(约4周)、medium_term(约6个月)、long_term(年) | +| `limit` | number | 否 | 返回的曲目数量(1-50) | +| `offset` | number | 否 | 返回的第一个曲目的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 用户 | + +### `spotify_get_top_artists` + +获取当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `time_range` | string | 否 | 时间范围:short_term(约4周)、medium_term(约6个月)、long_term(年) | +| `limit` | number | 否 | 返回的艺术家数量(1-50) | +| `offset` | number | 否 | 返回的第一个艺术家的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `artists` | array | 用户 | + +### `spotify_get_saved_tracks` + +获取当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 返回的曲目数量(1-50) | +| `offset` | number | 否 | 返回的第一个曲目的索引 | +| `market` | string | 否 | ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `tracks` | array | 用户 | + +### `spotify_save_tracks` + +将曲目保存到当前用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | 是 | 逗号分隔的 Spotify 曲目 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 曲目是否成功保存 | + +### `spotify_remove_saved_tracks` + +从用户中移除曲目 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | 是 | 逗号分隔的曲目 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 曲目是否成功移除 | + +### `spotify_check_saved_tracks` + +检查一个或多个曲目是否已保存到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `trackIds` | string | 是 | 逗号分隔的曲目 ID(最多 50 个) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `results` | json | 包含保存状态的曲目 ID 数组 | +| `all_saved` | boolean | 是否所有曲目都已保存 | +| `none_saved` | boolean | 是否没有曲目被保存 | + +### `spotify_get_recently_played` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `limit` | number | 否 | 返回的曲目数量 \(1-50\) | +| `after` | number | 否 | Unix 时间戳(毫秒)。返回此游标之后的项目。 | +| `before` | number | 否 | Unix 时间戳(毫秒)。返回此游标之前的项目。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `items` | array | 最近播放的曲目 | + +### `spotify_get_new_releases` + +获取 Spotify 中推荐的新专辑列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `country` | string | 否 | ISO 3166-1 alpha-2 国家代码 \(例如:"US", "GB"\) | +| `limit` | number | 否 | 返回的专辑数量 \(1-50\) | +| `offset` | number | 否 | 返回的第一个专辑的索引 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `albums` | json | 新专辑列表 | +| `total` | number | 新专辑的总数 | +| `next` | string | 下一页的 URL | + +### `spotify_get_categories` + +获取 Spotify 中用于标记项目的浏览类别列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `country` | string | 否 | ISO 3166-1 alpha-2 国家代码 \(例如:"US", "GB"\) | +| `locale` | string | 否 | 区域代码 \(例如:"en_US", "es_MX"\) | +| `limit` | number | 否 | 返回的类别数量 \(1-50\) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `categories` | json | 浏览类别列表 | +| `total` | number | 类别总数 | + +### `spotify_get_markets` + +获取 Spotify 可用的市场列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `markets` | json | ISO 国家代码列表 | + +### `spotify_get_playback_state` + +获取当前播放状态,包括设备、曲目和进度。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `market` | string | 否 | ISO 3166-1 alpha-2 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `is_playing` | boolean | 播放是否处于活动状态 | +| `device` | object | 活动设备信息 | +| `progress_ms` | number | 进度(毫秒) | +| `currently_playing_type` | string | 播放内容的类型 | +| `shuffle_state` | boolean | 是否启用了随机播放 | +| `repeat_state` | string | 循环模式(off, track, context) | +| `track` | object | 当前播放的曲目 | + +### `spotify_get_currently_playing` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `market` | string | 否 | 市场的 ISO 国家代码 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `is_playing` | boolean | 播放是否处于活动状态 | +| `progress_ms` | number | 当前曲目位置(毫秒) | +| `track` | json | 当前播放的曲目 | + +### `spotify_get_devices` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `devices` | array | 可用的播放设备 | + +### `spotify_get_queue` + +获取用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `currently_playing` | json | 当前播放的曲目 | +| `queue` | json | 队列中的即将播放曲目 | + +### `spotify_play` + +在 Spotify 上开始或恢复播放。可以播放特定的曲目、专辑或播放列表。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | 否 | 要播放的设备 ID。如果未提供,则在活动设备上播放。 | +| `context_uri` | string | 否 | 专辑、艺术家或播放列表的 Spotify URI(例如:"spotify:album:xxx") | +| `uris` | string | 否 | 逗号分隔的曲目 URI(例如:"spotify:track:xxx,spotify:track:yyy") | +| `offset` | number | 否 | 开始播放的上下文位置(从 0 开始的索引) | +| `position_ms` | number | 否 | 从曲目中的位置开始播放(以毫秒为单位) | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | 布尔值 | 播放是否成功启动 | + +### `spotify_pause` + +暂停 Spotify 上的播放。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `device_id` | 字符串 | 否 | 要暂停的设备 ID。如果未提供,则暂停活动设备。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | 布尔值 | 播放是否已暂停 | + +### `spotify_skip_next` + +跳到 Spotify 上的下一首曲目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `device_id` | 字符串 | 否 | 设备 ID。如果未提供,则使用活动设备。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | 布尔值 | 跳过是否成功 | + +### `spotify_skip_previous` + +跳到 Spotify 上的上一首曲目。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `device_id` | 字符串 | 否 | 设备 ID。如果未提供,则使用活动设备。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | 布尔值 | 跳过是否成功 | + +### `spotify_seek` + +跳到当前播放曲目中的某个位置。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `position_ms` | number | 是 | 要跳转到的位置(以毫秒为单位) | +| `device_id` | string | 否 | 目标设备 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否成功跳转 | + +### `spotify_add_to_queue` + +将曲目添加到用户 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `uri` | string | 是 | 要添加的曲目的 Spotify URI \(例如:"spotify:track:xxx"\) | +| `device_id` | string | 否 | 设备 ID。如果未提供,则使用活动设备。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否将曲目添加到队列 | + +### `spotify_set_volume` + +设置 Spotify 的播放音量。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `volume_percent` | number | 是 | 音量级别 \(0 到 100\) | +| `device_id` | string | 否 | 设备 ID。如果未提供,则使用活动设备。 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否设置了音量 | + +### `spotify_set_repeat` + +设置播放的重复模式。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `state` | string | 是 | 重复模式:"off"、"track" 或 "context" | +| `device_id` | string | 否 | 目标设备 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否成功设置了重复模式 | + +### `spotify_set_shuffle` + +打开或关闭随机播放。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `state` | boolean | 是 | true 表示打开随机播放,false 表示关闭 | +| `device_id` | string | 否 | 目标设备 ID | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否成功设置了随机播放 | + +### `spotify_transfer_playback` + +将播放转移到其他设备。 + +#### 输入 + +| 参数 | 类型 | 必需 | 描述 | +| --------- | ---- | -------- | ----------- | +| `device_id` | string | 是 | 要转移播放的目标设备 ID | +| `play` | boolean | 否 | 是否在新设备上开始播放 | + +#### 输出 + +| 参数 | 类型 | 描述 | +| --------- | ---- | ----------- | +| `success` | boolean | 是否成功转移播放 | + +## 注意 + +- 类别:`tools` +- 类型:`spotify` diff --git a/apps/docs/content/docs/zh/tools/zep.mdx b/apps/docs/content/docs/zh/tools/zep.mdx index 3f022d7b18..1a864df3d0 100644 --- a/apps/docs/content/docs/zh/tools/zep.mdx +++ b/apps/docs/content/docs/zh/tools/zep.mdx @@ -94,10 +94,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `context` | 字符串 | 上下文字符串(摘要或基本) | -| `facts` | 数组 | 提取的事实 | -| `entities` | 数组 | 提取的实体 | -| `summary` | 字符串 | 会话摘要 | +| `context` | string | 上下文字符串(摘要或基本模式) | ### `zep_get_messages` @@ -137,9 +134,9 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | -| `context` | string | 添加消息后的更新上下文 | -| `messageIds` | array | 添加的消息 UUID 数组 | | `threadId` | string | 线程 ID | +| `added` | boolean | 消息是否成功添加 | +| `messageIds` | array | 添加的消息 UUID 数组 | ### `zep_add_user` @@ -209,7 +206,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" | 参数 | 类型 | 描述 | | --------- | ---- | ----------- | | `threads` | array | 此用户的线程对象数组 | -| `userId` | string | 用户 ID | +| `totalCount` | number | 返回的线程总数 | ## 注意 diff --git a/apps/docs/i18n.lock b/apps/docs/i18n.lock index f0ee3ef0c3..5cf9a4ed6a 100644 --- a/apps/docs/i18n.lock +++ b/apps/docs/i18n.lock @@ -5925,7 +5925,7 @@ checksums: content/25: 371d0e46b4bd2c23f559b8bc112f6955 content/26: 1c1914a63d880607fa1f0ccaa47d6bdc content/27: bcadfc362b69078beee0088e5936c98b - content/28: dfba53a44a72ddb05d937ac850642c32 + content/28: 92c61c22136d02896171fccc6ade1f69 content/29: 25c0139e6dbae0caf7045db76d678057 content/30: c11a5d76541d3111055068edb43d26af content/31: 371d0e46b4bd2c23f559b8bc112f6955 @@ -5937,7 +5937,7 @@ checksums: content/37: 371d0e46b4bd2c23f559b8bc112f6955 content/38: 722e870ff0fd01d4bf8abf17bfc56110 content/39: bcadfc362b69078beee0088e5936c98b - content/40: edf9a72a6b185e4dc921c84774bef409 + content/40: 4e89b91d0a20c2e0ab0de5f93cfb4382 content/41: ffae7ab7fc862449bf8c47818726e36d content/42: 31375eb7944dce78bcba23c2e754f9e6 content/43: 371d0e46b4bd2c23f559b8bc112f6955 @@ -5955,7 +5955,7 @@ checksums: content/55: 371d0e46b4bd2c23f559b8bc112f6955 content/56: 094163dad0578662e2a3197dbf665a4e content/57: bcadfc362b69078beee0088e5936c98b - content/58: 74af50eceb2a5f514301c497a8e64030 + content/58: f2e1fb3bce0b54b10e312b5421f61707 content/59: b3f310d5ef115bea5a8b75bf25d7ea9a content/60: 549a9bd7ff92264fbd18c9d6e616594b 65891ef7e29a3ad2464222a998549ff5: @@ -48411,13 +48411,13 @@ checksums: content/77: 1168e89ec2162f8b1c0f4437e79d683b content/78: 1175fa4d6a946de24b5fb57d016f68c1 content/79: 371d0e46b4bd2c23f559b8bc112f6955 - content/80: 502dd72a174138e7888c41a31a445bc9 + content/80: b3d399422a0cc360275321cbf348c3fe content/81: bcadfc362b69078beee0088e5936c98b content/82: f194ced69b293f9f8d49d752f44caadb content/83: 90a2342ab1d3182265f81c9c7b94e800 content/84: a44f8a4284da46f9e6eea1418e4053d5 content/85: 371d0e46b4bd2c23f559b8bc112f6955 - content/86: f0be34514306abc1a6f2d43bba7c4743 + content/86: 6c0bde07d783bdd9c4dbc9295a9aad23 content/87: bcadfc362b69078beee0088e5936c98b content/88: 907a7c72c1cb1bbaa476500208058e61 content/89: 77b4c49ac2abbf3177723a26027f4b20 @@ -48455,7 +48455,7 @@ checksums: content/121: 371d0e46b4bd2c23f559b8bc112f6955 content/122: de3c6dc828985e7145637e03d3749170 content/123: bcadfc362b69078beee0088e5936c98b - content/124: f5157d6ea024ed45c55f8bed7516220a + content/124: fc1646564753a62ca90f9dc1dedd8dd8 content/125: b3f310d5ef115bea5a8b75bf25d7ea9a content/126: a7a0477ca54d01f3c0d815d727c47143 6bf4a002144862f19cec5ad8c2151fa3: @@ -49343,3 +49343,481 @@ checksums: content/16: a064887f5c777b54e029ba6ba1b56848 content/17: b3f310d5ef115bea5a8b75bf25d7ea9a content/18: a4748f8ce0a4667675ca03e4d9fef87b + 69ea9d99d8ef0b139c482d74509ab07b: + meta/title: 423cacfcc17c571c411a211fd0229cd4 + meta/description: 8c462ba6272aef51b1a0ffa7aac37fb5 + content/0: 1b031fb0c62c46b177aeed5c3d3f8f80 + content/1: b171b09b3f47764cf7aa827625194864 + content/2: 821e6394b0a953e2b0842b04ae8f3105 + content/3: 1670b89782aa1b50d232766d4ddc6ccd + content/4: 9c8aa3f09c9b2bd50ea4cdff3598ea4e + content/5: f70cf85dcd2c3cf7d46b01dc32aa10d6 + content/6: cc27d8fa96a722609186b19333d85814 + content/7: 371d0e46b4bd2c23f559b8bc112f6955 + content/8: 8bf8c43d7d7ae7278da7ebe6ecd356ac + content/9: bcadfc362b69078beee0088e5936c98b + content/10: 879f16545eaf9c61e35185b4129b64d4 + content/11: 8b880d3439aa74c33b9902d27c8a870d + content/12: 1467c26def4fe4ecc55fa200b40384b7 + content/13: 371d0e46b4bd2c23f559b8bc112f6955 + content/14: cf9b2ad21e039311bca96387146eeb87 + content/15: bcadfc362b69078beee0088e5936c98b + content/16: f61f5faf356f1a6b891cadbed34c84d2 + content/17: e29d2b102b3f58bd37638ea9210894bf + content/18: 378a38c76c0106c7209934794597d5d9 + content/19: 371d0e46b4bd2c23f559b8bc112f6955 + content/20: 83824e68c76b4a6e5c4fe62d58ea1c82 + content/21: bcadfc362b69078beee0088e5936c98b + content/22: 966cf37490e58a583d3958368df796fa + content/23: 8c81c45fda92e753c0dac4367973eac6 + content/24: ce0c05074a2bddbd40f5e26485ee5f06 + content/25: 371d0e46b4bd2c23f559b8bc112f6955 + content/26: e7c5338c8271763746e8ff8b6369183d + content/27: bcadfc362b69078beee0088e5936c98b + content/28: 227953269e44083ef3bc39218711cb05 + content/29: dc170a7f70ce32d5908cb1757103f8f8 + content/30: f2e6726730cf2f8612e10d0fdd03eaf8 + content/31: 371d0e46b4bd2c23f559b8bc112f6955 + content/32: 7ceeaac2d12299cae6e3892d6369ed9f + content/33: bcadfc362b69078beee0088e5936c98b + content/34: 8d2aeec4a01cda0a03816d9624b117c2 + content/35: ba00e04a0ff2e1a6a12d7aee62fa33f8 + content/36: 6d3896e9abe0f44805fecde59e52dfb4 + content/37: 371d0e46b4bd2c23f559b8bc112f6955 + content/38: 3310c3cd1e7ad3538d876973c5d4cd74 + content/39: bcadfc362b69078beee0088e5936c98b + content/40: aa4677bf16eb43aae63a4ae9ac57c5e5 + content/41: 08f5cdb1f569ac004040dbc0a0dfbce7 + content/42: 543a7893133239c24998013b6383a2ec + content/43: 371d0e46b4bd2c23f559b8bc112f6955 + content/44: f3505fc99976c10189a8bdd06281289a + content/45: bcadfc362b69078beee0088e5936c98b + content/46: b944979ca1b96c44154db7b38480f47a + content/47: ec85158684a17f7075c55ca5ba178c40 + content/48: 0508c2f54b25f8f31ed432805e094b0b + content/49: 371d0e46b4bd2c23f559b8bc112f6955 + content/50: 6e91b64186a5b220e8539b190991eca2 + content/51: bcadfc362b69078beee0088e5936c98b + content/52: ae001f604fd5ff92aef5797aa0094c2a + content/53: 47f7b5486bee09d1d0f2e5c976099ced + content/54: c096bcae5c582e9e060d3922549d3eb5 + content/55: 371d0e46b4bd2c23f559b8bc112f6955 + content/56: 6e91b64186a5b220e8539b190991eca2 + content/57: bcadfc362b69078beee0088e5936c98b + content/58: 68dc862efbc97d4bd6a12ea5e0bb768a + content/59: 3a43a63dc6dc7080da15db3e9cc3b7d9 + content/60: 507990b312b03294b9a70bf617a4f6f7 + content/61: 371d0e46b4bd2c23f559b8bc112f6955 + content/62: 6e91b64186a5b220e8539b190991eca2 + content/63: bcadfc362b69078beee0088e5936c98b + content/64: e4738365d87b2951f7284d2ed3a499ea + content/65: a5ff73112631e5d1f07812c7bafa8e1b + content/66: 8d56ee136021f3324dacf867b853038e + content/67: 371d0e46b4bd2c23f559b8bc112f6955 + content/68: 48338466c2390dc956c8d7e29dbe54e5 + content/69: bcadfc362b69078beee0088e5936c98b + content/70: 5939fda569e9e2470d0ec33c9e9f65c7 + content/71: 070ed023774d1aa1e25488372b52307e + content/72: a18e5c2a4cd9cf33e6ce14254b22ceba + content/73: 371d0e46b4bd2c23f559b8bc112f6955 + content/74: 4641cc3e4a6b63ce0e14c724b34017b8 + content/75: bcadfc362b69078beee0088e5936c98b + content/76: 976e478e3f2972d8ee3a245dfbe7b62e + content/77: 0e87446547d645d6a9d3bf4cdf1578e7 + content/78: 3211cb4fe3bc83c7c2b54399f0f9137c + content/79: 371d0e46b4bd2c23f559b8bc112f6955 + content/80: 84b2621db57916bbc9e1ff0533cb38e8 + content/81: bcadfc362b69078beee0088e5936c98b + content/82: 824ba104f268f10f2cc115913f6029ad + content/83: 64cc7298d2de7ceb78788d58d87898d9 + content/84: 74cd415dadcb38afdca3f733866a1aa7 + content/85: 371d0e46b4bd2c23f559b8bc112f6955 + content/86: 32660308667470b041bb2ad58ea661c1 + content/87: bcadfc362b69078beee0088e5936c98b + content/88: b029d32a6beabaca93723811cb26cd81 + content/89: 7115d89068cd7857095940eaf8e1bddd + content/90: 61d17e01d34a752b71157b8a005ba057 + content/91: 371d0e46b4bd2c23f559b8bc112f6955 + content/92: 1ab0a1bc823fcf2de657524ceea291af + content/93: bcadfc362b69078beee0088e5936c98b + content/94: a7c67f06628744551a9ae8179f2de2f1 + content/95: f309abdedd929f33810fffa5be8367c2 + content/96: 37feff6bad59c085b76fade5530b3cef + content/97: 371d0e46b4bd2c23f559b8bc112f6955 + content/98: f9b550860e44f6246a4f40c58c259b92 + content/99: bcadfc362b69078beee0088e5936c98b + content/100: f88ef41a0cd5601c4ce748b36f256253 + content/101: 675999bd8732f157f00284487dd610c7 + content/102: 543a7893133239c24998013b6383a2ec + content/103: 371d0e46b4bd2c23f559b8bc112f6955 + content/104: f6b0d1db4665a2bb31dfc8868b633e83 + content/105: bcadfc362b69078beee0088e5936c98b + content/106: db8f7f803591cdb0d53aa6f6aeeadac9 + content/107: 272d4f8e911da506722e66ea7fc06069 + content/108: 3ab139411b417c30e7473cad1ed374a1 + content/109: 371d0e46b4bd2c23f559b8bc112f6955 + content/110: 4735e0cc24471b2d1083dfde44bcccd5 + content/111: bcadfc362b69078beee0088e5936c98b + content/112: a205342d961d329a951066d1aeb9d344 + content/113: 325a0443a09a80a7795a3e53d790a608 + content/114: 907503eb014a7f0781237be119ed936c + content/115: 371d0e46b4bd2c23f559b8bc112f6955 + content/116: b3f1358de153b9dab2ef4c04d992965d + content/117: bcadfc362b69078beee0088e5936c98b + content/118: 0e244093c7c68d2993dba96d32d78814 + content/119: 1aa7fb20b2b2da0057d50edee1ee4804 + content/120: b413d3cb6cc735740d52686d859141ce + content/121: 371d0e46b4bd2c23f559b8bc112f6955 + content/122: 6c042d17fa1610528e0dda13884fd75d + content/123: bcadfc362b69078beee0088e5936c98b + content/124: c9febd022d469475d126e799d2ee3ddd + content/125: ad73b5cc613e18385c5b2b4d501d38cc + content/126: df462f7a572ad3994994f0ca76a68e76 + content/127: 371d0e46b4bd2c23f559b8bc112f6955 + content/128: 09899077a6a6b195512df6caf6c8fa01 + content/129: bcadfc362b69078beee0088e5936c98b + content/130: 12f0d6903559cb1120d4a3148dd381e7 + content/131: 9491f7740180102c9d049090daf5102a + content/132: 543a7893133239c24998013b6383a2ec + content/133: 371d0e46b4bd2c23f559b8bc112f6955 + content/134: ecc05074290b48ca06325410279a51dc + content/135: bcadfc362b69078beee0088e5936c98b + content/136: 106cc40304bb3b99875a664945d20653 + content/137: e903e245433fa0f0050609d0672c0cb5 + content/138: 9791cc374db8ab132621a0ae7ec50964 + content/139: 371d0e46b4bd2c23f559b8bc112f6955 + content/140: 77522579656cf07dd8643eb54962a3e6 + content/141: bcadfc362b69078beee0088e5936c98b + content/142: 97f12ce3c5e54f2b54792bf4eaeaa959 + content/143: 5420a194a8d33ad00076e768c1a299f6 + content/144: 2ef88df8b8a3684d125e9355a0dc57ce + content/145: 371d0e46b4bd2c23f559b8bc112f6955 + content/146: 77522579656cf07dd8643eb54962a3e6 + content/147: bcadfc362b69078beee0088e5936c98b + content/148: 25c2070b192a0c432f9c406fd3e68811 + content/149: 7e57012ba94aa52f9b0a10c121414454 + content/150: 7d384443444ff0f66076340b465adf8c + content/151: 371d0e46b4bd2c23f559b8bc112f6955 + content/152: 77522579656cf07dd8643eb54962a3e6 + content/153: bcadfc362b69078beee0088e5936c98b + content/154: 68f0fb5fb1c482871629a7ef6f68f401 + content/155: 5fcce1f516514f07d19ada48a67e64b9 + content/156: d0f8733556af6080f14f961a970d3ed2 + content/157: 371d0e46b4bd2c23f559b8bc112f6955 + content/158: 603d40532b35027d1070a1d511279dd7 + content/159: bcadfc362b69078beee0088e5936c98b + content/160: 8854a695814f9c3e5408024a6de4b874 + content/161: 38824704803684b47120f90d72c4d1f3 + content/162: fae2b8c0813d8c4a16cfc1a939557b12 + content/163: 371d0e46b4bd2c23f559b8bc112f6955 + content/164: 3e87387b13c5a32cf60e79e288081d2a + content/165: bcadfc362b69078beee0088e5936c98b + content/166: e611f1b9fcd2ec209f7e8c541da0d334 + content/167: e23262668801f4e01b1705bf2e06dbb9 + content/168: 543a7893133239c24998013b6383a2ec + content/169: 371d0e46b4bd2c23f559b8bc112f6955 + content/170: ea6bfafd502021032c8461583d575003 + content/171: bcadfc362b69078beee0088e5936c98b + content/172: fc2291a33dbe5fb5a8e6e9fba4a962e5 + content/173: 465f3cda4842dcbd91914420c94e7e2c + content/174: 0827bafb8fd84e5d2c941a5ba49180f9 + content/175: 371d0e46b4bd2c23f559b8bc112f6955 + content/176: 80d9e59852604254bbea9b5b429a56a9 + content/177: bcadfc362b69078beee0088e5936c98b + content/178: e48a4a4332a93d669ae9d6734faf52ed + content/179: f4b3dc25c15cd089a940c3f87e1682cb + content/180: 29fcda568d59b51927e5032fea029bbb + content/181: 371d0e46b4bd2c23f559b8bc112f6955 + content/182: 80d9e59852604254bbea9b5b429a56a9 + content/183: bcadfc362b69078beee0088e5936c98b + content/184: d5fc19166d3a3cea8b8d2d50f0d563bb + content/185: d094dd11ce2f71593989b9f08ef50d1c + content/186: ecc367223a7d500e39174238f904c96b + content/187: 371d0e46b4bd2c23f559b8bc112f6955 + content/188: 80d9e59852604254bbea9b5b429a56a9 + content/189: bcadfc362b69078beee0088e5936c98b + content/190: 965bce63781360c2d25225ef73ab2be6 + content/191: 91d09906a52576aca688686d68fe98c3 + content/192: 0ef50aac80634edc58281abaf4c172de + content/193: 371d0e46b4bd2c23f559b8bc112f6955 + content/194: 52d31c23ea85ff2429d9ffa3304764f7 + content/195: bcadfc362b69078beee0088e5936c98b + content/196: e6f6c7f9ebe48b0904f00e22dc7fa6a5 + content/197: 22e79701e2b405b16f3ec3eb1c45ab6e + content/198: 6c49f8ce476f21412e4d9ab21dd99a35 + content/199: 371d0e46b4bd2c23f559b8bc112f6955 + content/200: ef7d5b6b00dec889debfa44a73912f00 + content/201: bcadfc362b69078beee0088e5936c98b + content/202: d0c41bb0907153104dbdc410f9f8bdb2 + content/203: 33429e717ec12c6c21aaf8c08cebf59d + content/204: 0e8ff53af4c52be00d5dd6f6089e9eb6 + content/205: 371d0e46b4bd2c23f559b8bc112f6955 + content/206: 5fd8c99db5befe8b23fd5a689ce113a7 + content/207: bcadfc362b69078beee0088e5936c98b + content/208: 6e076a87026c2bd5cec3f1e3f41f03e5 + content/209: d0563ce6c297585d9c9597190d55dca4 + content/210: 543a7893133239c24998013b6383a2ec + content/211: 371d0e46b4bd2c23f559b8bc112f6955 + content/212: ce48d31c56d3bf55875623e232e3a4f7 + content/213: bcadfc362b69078beee0088e5936c98b + content/214: f05f834e80d44f4b261ed70444986784 + content/215: cc504b22e453c680bd5af9b7346a9b16 + content/216: c09610268eeccf0bfd34ebd5dd35c007 + content/217: 371d0e46b4bd2c23f559b8bc112f6955 + content/218: b367871da0561ad3c5d7dacf2cb9a176 + content/219: bcadfc362b69078beee0088e5936c98b + content/220: 85e1990e4f26720de4b40a1bc42a3e32 + content/221: f630cb95b06d7aad74eb3ee3061ea255 + content/222: ff11171170fa01ddfe1b54a6a9b7bf7e + content/223: 371d0e46b4bd2c23f559b8bc112f6955 + content/224: b367871da0561ad3c5d7dacf2cb9a176 + content/225: bcadfc362b69078beee0088e5936c98b + content/226: 2b9e1aad4a556211a265a182cbe25a05 + content/227: 40965cc40257c6bd2be2cac20c5dfccb + content/228: 257fbd87a9b8b1c20190b5b91b304c37 + content/229: 371d0e46b4bd2c23f559b8bc112f6955 + content/230: b367871da0561ad3c5d7dacf2cb9a176 + content/231: bcadfc362b69078beee0088e5936c98b + content/232: 55cb78c8d67ffcf7ada95dcc00bde23c + content/233: 6cef845ded645616c419d28bad1d6f9e + content/234: ba43c5aeb8f25faf46f26bf55b19bff1 + content/235: 371d0e46b4bd2c23f559b8bc112f6955 + content/236: 44115089ae4f362d5b4039b17ade418c + content/237: bcadfc362b69078beee0088e5936c98b + content/238: c3d9c66aa878494de5e962966252bcd4 + content/239: ed22ba9ba05d9a98ddf5c52c37df20bd + content/240: 2cf208e195bb91c07ad9e53e948f6ddf + content/241: 371d0e46b4bd2c23f559b8bc112f6955 + content/242: e6ef31303aa260ffd54368f310718c60 + content/243: bcadfc362b69078beee0088e5936c98b + content/244: e8f550ccf6f5146969dc94e230896468 + content/245: 4fb261f05c50668d4dbf59cb5b33187c + content/246: ca25da475b2c19ca9365eb40a3e883ef + content/247: 371d0e46b4bd2c23f559b8bc112f6955 + content/248: 014b7067c2080c6778a1c5af5786de1f + content/249: bcadfc362b69078beee0088e5936c98b + content/250: 420275dbc42f605397d2e5d792dd0ec6 + content/251: e3ae93e2557ade9f9101c7d7002ebae2 + content/252: 41be55e87cb49923a825c78943f87cda + content/253: 371d0e46b4bd2c23f559b8bc112f6955 + content/254: c86d375921bcc75708fbdcee104151e3 + content/255: bcadfc362b69078beee0088e5936c98b + content/256: 49208ed01fcf6816c16f9be9c609bc3f + content/257: d786589994cd61d6822c95ef9bade462 + content/258: e2a3bd59ba9f74919e79722d01b2cd08 + content/259: 371d0e46b4bd2c23f559b8bc112f6955 + content/260: fe4f450f29f2ab131ab01c1e3418050f + content/261: bcadfc362b69078beee0088e5936c98b + content/262: f0acbbe591b2053cfb0ff4592ada342d + content/263: 1e55ca66a9625b7e5d1d402a7b8ad866 + content/264: 6191ceb51b5788eab069f6f9445ac7d9 + content/265: 371d0e46b4bd2c23f559b8bc112f6955 + content/266: ad4f64f06c612d941d8caf1241539721 + content/267: bcadfc362b69078beee0088e5936c98b + content/268: f48fcfa0a3ed81e1a5090d7023745106 + content/269: 02c6f039913ad3d9aeb4d64940b144a7 + content/270: 3adfe68791a044e51a37c630a1164083 + content/271: 371d0e46b4bd2c23f559b8bc112f6955 + content/272: 4c6876bac6fc6e63bdfa336ed8287e82 + content/273: bcadfc362b69078beee0088e5936c98b + content/274: 267cca917156e53a0a7191ea3b654dd2 + content/275: 7f59ca32e2e37a892ec0fa0106980689 + content/276: 837fe390f427bf342fdb347f660b8e24 + content/277: 371d0e46b4bd2c23f559b8bc112f6955 + content/278: 1e0346d0d1a808956842f5834a9a4ca7 + content/279: bcadfc362b69078beee0088e5936c98b + content/280: 41138a38aa9cc6bf8d202404de595669 + content/281: bfe437d8120b3bfdcb3d32f8baaa08cc + content/282: a45b4af8c2f1ce76300a770abfdb4586 + content/283: 371d0e46b4bd2c23f559b8bc112f6955 + content/284: b13666816ba70de0836700f0baa6a3cd + content/285: bcadfc362b69078beee0088e5936c98b + content/286: 41138a38aa9cc6bf8d202404de595669 + content/287: 4d891a03094ba52d969bde716a26ef79 + content/288: f00b571a9ab7a024a1b7256850110465 + content/289: 371d0e46b4bd2c23f559b8bc112f6955 + content/290: 285d1aaab77d5d2c1c6e3414c498458b + content/291: bcadfc362b69078beee0088e5936c98b + content/292: f3bb7d23cf26b0729d5c2bd050ee2f3d + content/293: cc51bfd76f006cb46a1f0971bf6725b3 + content/294: 0740301dc6622444bf888739959cd064 + content/295: 371d0e46b4bd2c23f559b8bc112f6955 + content/296: dbaa8157daa175b74bf24a7a344d9b50 + content/297: bcadfc362b69078beee0088e5936c98b + content/298: f3bb7d23cf26b0729d5c2bd050ee2f3d + content/299: 99c6883c74ac9ff2029bf9a993d108b2 + content/300: 8888ecab4b3b39f2359344b27297b9fc + content/301: 371d0e46b4bd2c23f559b8bc112f6955 + content/302: 725e1460c8d7e77af73130661211832b + content/303: bcadfc362b69078beee0088e5936c98b + content/304: 8d16e692f351c8018a19ebe10b42e600 + content/305: 4c657061119501c3e92e44e2e1d34872 + content/306: 47e2cc0eeec5f2cb91d830348d233911 + content/307: 371d0e46b4bd2c23f559b8bc112f6955 + content/308: 014b7067c2080c6778a1c5af5786de1f + content/309: bcadfc362b69078beee0088e5936c98b + content/310: 0a27f1dece5205a1fdad782471983af0 + content/311: 208d2fe38550193159f17e05de690d3a + content/312: 3d1d49231eeb2920ffb765feb9099fd7 + content/313: 371d0e46b4bd2c23f559b8bc112f6955 + content/314: ac5aa666db2990b8e5c9328d435e6f2f + content/315: bcadfc362b69078beee0088e5936c98b + content/316: 63c2bbaa67c1f21c8394137da481c35c + content/317: d3fc31382a8b93b5798b0a8204200e9a + content/318: 41be55e87cb49923a825c78943f87cda + content/319: 371d0e46b4bd2c23f559b8bc112f6955 + content/320: d71b6bb8e2dd6ce98101aec6a1dd77f2 + content/321: bcadfc362b69078beee0088e5936c98b + content/322: 04a5b82cf37aba4a903f9fd607bf4321 + content/323: a981995f0ce1ff26f910fa3f14084258 + content/324: bb1385dbf0bd4ca26e69ee7259049758 + content/325: 371d0e46b4bd2c23f559b8bc112f6955 + content/326: b2cea0326a67f273c57fa21d72669c2d + content/327: bcadfc362b69078beee0088e5936c98b + content/328: 5f48c7eab78092422ecf5b876f38f5d6 + content/329: 5465f9813e73a2b2434f093ae9f9e4fe + content/330: 41be55e87cb49923a825c78943f87cda + content/331: 371d0e46b4bd2c23f559b8bc112f6955 + content/332: 5043d4e44428c5608442876f605f8fbf + content/333: bcadfc362b69078beee0088e5936c98b + content/334: 87050e58efe03557a55e784813899b25 + content/335: 7daa967e284f004f64c8fbcac1dabd6d + content/336: 41be55e87cb49923a825c78943f87cda + content/337: 371d0e46b4bd2c23f559b8bc112f6955 + content/338: 245d9a70b38a1b43467510b43b1dfd0b + content/339: bcadfc362b69078beee0088e5936c98b + content/340: b8b046b580b425b46ee97042b007cb5c + content/341: c516d20b10d7d47f9250156fdc05b51b + content/342: 41be55e87cb49923a825c78943f87cda + content/343: 371d0e46b4bd2c23f559b8bc112f6955 + content/344: d3f7cf28e23f03c6ccd3c322a0dfcf7a + content/345: bcadfc362b69078beee0088e5936c98b + content/346: 87050e58efe03557a55e784813899b25 + content/347: 93e76f13a0b2468f443b0addf2f5b426 + content/348: fd835a0491ef404f10f95a64a8d799d7 + content/349: 371d0e46b4bd2c23f559b8bc112f6955 + content/350: 9330190b54228f4946546d6c918d362a + content/351: bcadfc362b69078beee0088e5936c98b + content/352: ef38c832c7c3e8a7912326a82e8e152d + content/353: cdbda4d943cce1c1e6cee284cd9499ba + content/354: afcdfbbd50590cddc8f328231183ffc7 + content/355: 371d0e46b4bd2c23f559b8bc112f6955 + content/356: 08b384a0452ac039fcd5a10c700887ef + content/357: bcadfc362b69078beee0088e5936c98b + content/358: 29bf3a3adb2e03579ce3067c31000cfe + content/359: ba0f72f52c6c1b69eb4b7ed77ace3eed + content/360: a0f850e27892642967e8387d236c7d3d + content/361: 371d0e46b4bd2c23f559b8bc112f6955 + content/362: b1085b1b1b2cacf24e21dab7e53275ef + content/363: bcadfc362b69078beee0088e5936c98b + content/364: 3224246af0e256d3b1cebc4f5d4af7b8 + content/365: 2b7033832f71a1afea2ad0de1a4eb0f6 + content/366: 543a7893133239c24998013b6383a2ec + content/367: 371d0e46b4bd2c23f559b8bc112f6955 + content/368: dacda77a1a1e6eb1fb09681a03b16b39 + content/369: bcadfc362b69078beee0088e5936c98b + content/370: f92ddf910a76ccfba44526b5fc9e18eb + content/371: e5df0bf9989c8fb4bb8cc84bbc2893aa + content/372: 8d8179708a474294e5c18aa0f4c8e211 + content/373: 371d0e46b4bd2c23f559b8bc112f6955 + content/374: 13d49b60016c99dab88b976bc726dff2 + content/375: bcadfc362b69078beee0088e5936c98b + content/376: 540cebf1a23579cbff89a8471080e513 + content/377: 2316cd35c407ec12007f9791d7addc5d + content/378: 6a8a257b30c96326fb03188c00a8b89f + content/379: 371d0e46b4bd2c23f559b8bc112f6955 + content/380: e9732d548f74b7cc7d045c755255d14b + content/381: bcadfc362b69078beee0088e5936c98b + content/382: d01baf6d3458f3e6ac1e1b93adbedc85 + content/383: f04f7c69567c6d4641432928dd8fbbe0 + content/384: 186964792066e564d16712d000144cfc + content/385: 371d0e46b4bd2c23f559b8bc112f6955 + content/386: d71b6bb8e2dd6ce98101aec6a1dd77f2 + content/387: bcadfc362b69078beee0088e5936c98b + content/388: 23531b030992d6af95a46fedf7ebba2d + content/389: 99e642e2d7e14f2de122fd31c8cc05a2 + content/390: 67cb0568fb3a1ec30492380da7a07d76 + content/391: 371d0e46b4bd2c23f559b8bc112f6955 + content/392: 9dfe50ce64c70b434d17598a4ac8234b + content/393: bcadfc362b69078beee0088e5936c98b + content/394: ed2143e277e57380a95890c21950efa6 + content/395: 0c6c2544d0bacb6f0f6fd613d858789a + content/396: 543a7893133239c24998013b6383a2ec + content/397: 371d0e46b4bd2c23f559b8bc112f6955 + content/398: 6600803515bc80ef0b1a567c49794a6f + content/399: bcadfc362b69078beee0088e5936c98b + content/400: 36e4192fe30f586d12f1617efd6ef404 + content/401: 6e7203406297c99cb022bb5c6afe0835 + content/402: 543a7893133239c24998013b6383a2ec + content/403: 371d0e46b4bd2c23f559b8bc112f6955 + content/404: d71b6bb8e2dd6ce98101aec6a1dd77f2 + content/405: bcadfc362b69078beee0088e5936c98b + content/406: e30243efbaf6344a2588df16b7b03284 + content/407: 16310c021653f143fa83827a9e4f3a34 + content/408: 543a7893133239c24998013b6383a2ec + content/409: 371d0e46b4bd2c23f559b8bc112f6955 + content/410: d71b6bb8e2dd6ce98101aec6a1dd77f2 + content/411: bcadfc362b69078beee0088e5936c98b + content/412: 967acf2732882d79bbfbbb09157f5754 + content/413: 80faf4b7ad34e672124993b741af2632 + content/414: 513b1bd1010130caba927d7cb4ad317d + content/415: 371d0e46b4bd2c23f559b8bc112f6955 + content/416: 683cb2f65472983ba73b76bd7b6e2d13 + content/417: bcadfc362b69078beee0088e5936c98b + content/418: a6bb59aed6ec6c5cbc6380c07e5d875d + content/419: 020bf7263ea4bfdd38b730a5d97a1d27 + content/420: c5a66ae6dd3d38e0955ddc199b241f94 + content/421: 371d0e46b4bd2c23f559b8bc112f6955 + content/422: e670ca8583015c3bbeaa9f0e04dc07e7 + content/423: bcadfc362b69078beee0088e5936c98b + content/424: e35f604c54faeba3ab9cc9222b008e13 + content/425: fcf4b372290efddeafde18f874cb9056 + content/426: af6ffdf3979d631c1c0f3ce41aabcf56 + content/427: 371d0e46b4bd2c23f559b8bc112f6955 + content/428: f4d2b9c6ac152adb8676d09177e356bb + content/429: bcadfc362b69078beee0088e5936c98b + content/430: 49bc6ae2d6952bc9ff409d41bb0d21be + content/431: 4d6e4bbe907d379c3fbf703ab58b3022 + content/432: 5536b11f94c6e96cc8ecb198bcf53ca7 + content/433: 371d0e46b4bd2c23f559b8bc112f6955 + content/434: f4d2b9c6ac152adb8676d09177e356bb + content/435: bcadfc362b69078beee0088e5936c98b + content/436: 49bc6ae2d6952bc9ff409d41bb0d21be + content/437: fd10df2f8761ee35226d0093777bdf6d + content/438: 95260d57dd53c9c3b7fe9429257e767e + content/439: 371d0e46b4bd2c23f559b8bc112f6955 + content/440: 826b5d8ecc169a1e377687ac028040f5 + content/441: bcadfc362b69078beee0088e5936c98b + content/442: 840756181376b103737fda44d21a98f6 + content/443: 70fe3481a60a82c17db681eced11eada + content/444: e974d6f1cc3444d6f44495180e69b05e + content/445: 371d0e46b4bd2c23f559b8bc112f6955 + content/446: 9921ba4d4de84198b763bc0bde6b03b3 + content/447: bcadfc362b69078beee0088e5936c98b + content/448: d5f105ab1237fca610d09608b3b4e88d + content/449: 5b3b40dab522c857510f51a63237293c + content/450: 030bf2ff87d6c11732b684f306b4d2f5 + content/451: 371d0e46b4bd2c23f559b8bc112f6955 + content/452: 9ed3acd5390461eeb6414faf0a1a512e + content/453: bcadfc362b69078beee0088e5936c98b + content/454: eaca3ee3a7d41ebd10e3ede6127bf459 + content/455: bf893edcd95310e98a3af9e73cdaae60 + content/456: c0b33fa82175a4cc6ad90b02c67713b9 + content/457: 371d0e46b4bd2c23f559b8bc112f6955 + content/458: f82a23358be57576d645fa76c0955391 + content/459: bcadfc362b69078beee0088e5936c98b + content/460: 834d3f74c39b74e6aa4c99ccd13a46e8 + content/461: 67c97a416e8abeb8d61893c3f5ac17fd + content/462: c2f07afc0743347406fb9c9b98690997 + content/463: 371d0e46b4bd2c23f559b8bc112f6955 + content/464: 44d040b1598cbd8043043cb270da5bbb + content/465: bcadfc362b69078beee0088e5936c98b + content/466: c1a8cbf38b2a8480ea70243b38d509bc + content/467: dc3a650eefb9d65f582bfee6517ac2f9 + content/468: 883277a3e47c7476d6356dc48df6c257 + content/469: 371d0e46b4bd2c23f559b8bc112f6955 + content/470: 96d428e4bb2231882653c845b590469b + content/471: bcadfc362b69078beee0088e5936c98b + content/472: dbc5fceeefb3ab5fa505394becafef4e + content/473: b3f310d5ef115bea5a8b75bf25d7ea9a + content/474: 27c398e669b297cea076e4ce4cc0c5eb From 9c8d845ba47819b3fd77627e9482c8ce64a544f4 Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 12 Dec 2025 21:05:26 -0800 Subject: [PATCH 34/34] feat(ui): added component playground & fixed training modal (#2354) --- apps/sim/app/playground/page.tsx | 566 ++++++++++++ .../w/[workflowId]/components/index.ts | 1 - .../components/terminal/terminal.tsx | 129 +++ .../training-controls/training-controls.tsx | 40 - .../training-floating-button.tsx | 78 -- .../training-controls/training-modal.tsx | 866 +++++++++--------- .../[workspaceId]/w/[workflowId]/workflow.tsx | 10 +- apps/sim/lib/core/config/env.ts | 4 +- 8 files changed, 1155 insertions(+), 539 deletions(-) create mode 100644 apps/sim/app/playground/page.tsx delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/training-controls/training-controls.tsx delete mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/training-controls/training-floating-button.tsx diff --git a/apps/sim/app/playground/page.tsx b/apps/sim/app/playground/page.tsx new file mode 100644 index 0000000000..7a3804211a --- /dev/null +++ b/apps/sim/app/playground/page.tsx @@ -0,0 +1,566 @@ +'use client' + +import { useState } from 'react' +import { ArrowLeft, Bell, Folder, Key, Settings, User } from 'lucide-react' +import { notFound, useRouter } from 'next/navigation' +import { + Badge, + Breadcrumb, + BubbleChatPreview, + Button, + Card as CardIcon, + ChevronDown, + Code, + Combobox, + Connections, + Copy, + DocumentAttachment, + Duplicate, + Eye, + FolderCode, + FolderPlus, + HexSimple, + Input, + Key as KeyIcon, + Label, + Layout, + Library, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + ModalTabs, + ModalTabsContent, + ModalTabsList, + ModalTabsTrigger, + ModalTrigger, + MoreHorizontal, + NoWrap, + PanelLeft, + Play, + Popover, + PopoverBackButton, + PopoverContent, + PopoverFolder, + PopoverItem, + PopoverScrollArea, + PopoverSearch, + PopoverSection, + PopoverTrigger, + Redo, + Rocket, + SModal, + SModalContent, + SModalMain, + SModalMainBody, + SModalMainHeader, + SModalSidebar, + SModalSidebarHeader, + SModalSidebarItem, + SModalSidebarSection, + SModalSidebarSectionTitle, + SModalTrigger, + Switch, + Textarea, + Tooltip, + Trash, + Trash2, + Undo, + Wrap, + ZoomIn, + ZoomOut, +} from '@/components/emcn' +import { env, isTruthy } from '@/lib/core/config/env' + +function Section({ title, children }: { title: string; children: React.ReactNode }) { + return ( +
+

+ {title} +

+
{children}
+
+ ) +} + +function VariantRow({ label, children }: { label: string; children: React.ReactNode }) { + return ( +
+ {label} +
{children}
+
+ ) +} + +const SAMPLE_CODE = `function greet(name) { + console.log("Hello, " + name); + return { success: true }; +}` + +const SAMPLE_PYTHON = `def greet(name): + print(f"Hello, {name}") + return {"success": True}` + +const COMBOBOX_OPTIONS = [ + { label: 'Option 1', value: 'opt1' }, + { label: 'Option 2', value: 'opt2' }, + { label: 'Option 3', value: 'opt3' }, +] + +export default function PlaygroundPage() { + const router = useRouter() + const [comboboxValue, setComboboxValue] = useState('') + const [switchValue, setSwitchValue] = useState(false) + const [activeTab, setActiveTab] = useState('profile') + + if (!isTruthy(env.NEXT_PUBLIC_ENABLE_PLAYGROUND)) { + notFound() + } + + return ( + +
+ + + + + Go back + +
+
+

+ EMCN Component Playground +

+

+ All emcn UI components and their variants +

+
+ + {/* Button */} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + {/* Badge */} +
+ + Default + + + Outline + +
+ + {/* Input */} +
+ + + + + + +
+ + {/* Textarea */} +
+