mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-20 04:17:57 -05:00
improvement(tools): added visibility for tools that were missing it, added new google and github tools (#2874)
* improvement(tools): added visibility for tools that were missing it, added new google tools * fixed the name for google forms * revert schema enrichers change * fixed block ordering
This commit is contained in:
@@ -1535,4 +1535,800 @@ Delete a GitHub Project V2. This action is permanent and cannot be undone. Requi
|
||||
| `number` | number | Deleted project number |
|
||||
| `url` | string | Deleted project URL |
|
||||
|
||||
### `github_search_code`
|
||||
|
||||
Search for code across GitHub repositories. Use qualifiers like repo:owner/name, language:js, path:src, extension:py
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `q` | string | Yes | Search query with optional qualifiers \(repo:, language:, path:, extension:, user:, org:\) |
|
||||
| `sort` | string | No | Sort by indexed date \(default: best match\) |
|
||||
| `order` | string | No | Sort order: asc or desc \(default: desc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `total_count` | number | Total matching results |
|
||||
| `incomplete_results` | boolean | Whether results are incomplete |
|
||||
| `items` | array | Array of code matches from GitHub API |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `path` | string | File path |
|
||||
| ↳ `sha` | string | Blob SHA |
|
||||
| ↳ `html_url` | string | GitHub web URL |
|
||||
| ↳ `repository` | object | Repository object |
|
||||
|
||||
### `github_search_commits`
|
||||
|
||||
Search for commits across GitHub. Use qualifiers like repo:owner/name, author:user, committer:user, author-date:>2023-01-01
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `q` | string | Yes | Search query with optional qualifiers \(repo:, author:, committer:, author-date:, committer-date:, merge:true/false\) |
|
||||
| `sort` | string | No | Sort by: author-date or committer-date \(default: best match\) |
|
||||
| `order` | string | No | Sort order: asc or desc \(default: desc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `total_count` | number | Total matching results |
|
||||
| `incomplete_results` | boolean | Whether results are incomplete |
|
||||
| `items` | array | Array of commit objects from GitHub API |
|
||||
| ↳ `sha` | string | Commit SHA |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `commit` | object | Commit data |
|
||||
| ↳ `author` | object | GitHub user |
|
||||
| ↳ `committer` | object | GitHub user |
|
||||
| ↳ `repository` | object | Repository |
|
||||
|
||||
### `github_search_issues`
|
||||
|
||||
Search for issues and pull requests across GitHub. Use qualifiers like repo:owner/name, is:issue, is:pr, state:open, label:bug, author:user
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `q` | string | Yes | Search query with optional qualifiers \(repo:, is:issue, is:pr, state:, label:, author:, assignee:\) |
|
||||
| `sort` | string | No | Sort by: comments, reactions, created, updated, interactions \(default: best match\) |
|
||||
| `order` | string | No | Sort order: asc or desc \(default: desc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `total_count` | number | Total matching results |
|
||||
| `incomplete_results` | boolean | Whether results are incomplete |
|
||||
| `items` | array | Array of issue/PR objects from GitHub API |
|
||||
| ↳ `id` | number | Issue ID |
|
||||
| ↳ `number` | number | Issue number |
|
||||
| ↳ `title` | string | Title |
|
||||
| ↳ `state` | string | State |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `body` | string | Body text |
|
||||
| ↳ `user` | object | Author |
|
||||
| ↳ `labels` | array | Labels |
|
||||
| ↳ `assignees` | array | Assignees |
|
||||
| ↳ `created_at` | string | Creation date |
|
||||
| ↳ `updated_at` | string | Update date |
|
||||
| ↳ `closed_at` | string | Close date |
|
||||
|
||||
### `github_search_repos`
|
||||
|
||||
Search for repositories across GitHub. Use qualifiers like language:python, stars:>1000, topic:react, user:owner, org:name
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `q` | string | Yes | Search query with optional qualifiers \(language:, stars:, forks:, topic:, user:, org:, in:name,description,readme\) |
|
||||
| `sort` | string | No | Sort by: stars, forks, help-wanted-issues, updated \(default: best match\) |
|
||||
| `order` | string | No | Sort order: asc or desc \(default: desc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `total_count` | number | Total matching results |
|
||||
| `incomplete_results` | boolean | Whether results are incomplete |
|
||||
| `items` | array | Array of repository objects from GitHub API |
|
||||
| ↳ `id` | number | Repository ID |
|
||||
| ↳ `full_name` | string | Full name |
|
||||
| ↳ `description` | string | Description |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `stargazers_count` | number | Stars |
|
||||
| ↳ `forks_count` | number | Forks |
|
||||
| ↳ `open_issues_count` | number | Open issues |
|
||||
| ↳ `language` | string | Language |
|
||||
| ↳ `topics` | array | Topics |
|
||||
| ↳ `owner` | object | Owner |
|
||||
|
||||
### `github_search_users`
|
||||
|
||||
Search for users and organizations on GitHub. Use qualifiers like type:user, type:org, followers:>1000, repos:>10, location:city
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `q` | string | Yes | Search query with optional qualifiers \(type:user/org, followers:, repos:, location:, language:, created:\) |
|
||||
| `sort` | string | No | Sort by: followers, repositories, joined \(default: best match\) |
|
||||
| `order` | string | No | Sort order: asc or desc \(default: desc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `total_count` | number | Total matching results |
|
||||
| `incomplete_results` | boolean | Whether results are incomplete |
|
||||
| `items` | array | Array of user objects from GitHub API |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `login` | string | Username |
|
||||
| ↳ `html_url` | string | Profile URL |
|
||||
| ↳ `avatar_url` | string | Avatar URL |
|
||||
| ↳ `type` | string | User or Organization |
|
||||
| ↳ `site_admin` | boolean | Is site admin |
|
||||
|
||||
### `github_list_commits`
|
||||
|
||||
List commits in a repository with optional filtering by SHA, path, author, committer, or date range
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `sha` | string | No | SHA or branch to start listing commits from |
|
||||
| `path` | string | No | Only commits containing this file path |
|
||||
| `author` | string | No | GitHub login or email address to filter by author |
|
||||
| `committer` | string | No | GitHub login or email address to filter by committer |
|
||||
| `since` | string | No | Only commits after this date \(ISO 8601 format\) |
|
||||
| `until` | string | No | Only commits before this date \(ISO 8601 format\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `items` | array | Array of commit objects from GitHub API |
|
||||
| ↳ `sha` | string | Commit SHA |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `commit` | object | Commit data |
|
||||
| ↳ `author` | object | GitHub user |
|
||||
| ↳ `committer` | object | GitHub user |
|
||||
| ↳ `parents` | array | Parent commits |
|
||||
| `count` | number | Number of commits returned |
|
||||
|
||||
### `github_get_commit`
|
||||
|
||||
Get detailed information about a specific commit including files changed and stats
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `ref` | string | Yes | Commit SHA, branch name, or tag name |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `sha` | string | Commit SHA |
|
||||
| `html_url` | string | Web URL |
|
||||
| `commit` | object | Commit data |
|
||||
| `author` | object | GitHub user |
|
||||
| `committer` | object | GitHub user |
|
||||
| `stats` | object | Change stats |
|
||||
| `files` | array | Changed files |
|
||||
| `parents` | array | Parent commits |
|
||||
|
||||
### `github_compare_commits`
|
||||
|
||||
Compare two commits or branches to see the diff, commits between them, and changed files
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `base` | string | Yes | Base branch/tag/SHA for comparison |
|
||||
| `head` | string | Yes | Head branch/tag/SHA for comparison |
|
||||
| `per_page` | number | No | Results per page for files \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number for files \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `status` | string | Comparison status |
|
||||
| `ahead_by` | number | Commits ahead |
|
||||
| `behind_by` | number | Commits behind |
|
||||
| `total_commits` | number | Total commits |
|
||||
| `html_url` | string | Web URL |
|
||||
| `diff_url` | string | Diff URL |
|
||||
| `patch_url` | string | Patch URL |
|
||||
| `base_commit` | object | Base commit |
|
||||
| `merge_base_commit` | object | Merge base |
|
||||
| `commits` | array | Commits between |
|
||||
| `files` | array | Changed files |
|
||||
|
||||
### `github_create_gist`
|
||||
|
||||
Create a new gist with one or more files
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `description` | string | No | Description of the gist |
|
||||
| `files` | json | Yes | JSON object with filenames as keys and content as values. Example: \{"file.txt": \{"content": "Hello"\}\} |
|
||||
| `Example` | string | No | No description |
|
||||
| `public` | boolean | No | Whether the gist is public \(default: false\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Gist ID |
|
||||
| `html_url` | string | Web URL |
|
||||
| `git_pull_url` | string | Git pull URL |
|
||||
| `git_push_url` | string | Git push URL |
|
||||
| `description` | string | Description |
|
||||
| `public` | boolean | Is public |
|
||||
| `created_at` | string | Creation date |
|
||||
| `updated_at` | string | Update date |
|
||||
| `files` | object | Files in gist |
|
||||
| `owner` | object | Owner info |
|
||||
|
||||
### `github_get_gist`
|
||||
|
||||
Get a gist by ID including its file contents
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Gist ID |
|
||||
| `html_url` | string | Web URL |
|
||||
| `description` | string | Description |
|
||||
| `public` | boolean | Is public |
|
||||
| `created_at` | string | Creation date |
|
||||
| `updated_at` | string | Update date |
|
||||
| `files` | object | Files with content |
|
||||
| `owner` | object | Owner info |
|
||||
| `comments` | number | Comment count |
|
||||
|
||||
### `github_list_gists`
|
||||
|
||||
List gists for a user or the authenticated user
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `username` | string | No | GitHub username \(omit for authenticated user's gists\) |
|
||||
| `since` | string | No | Only gists updated after this time \(ISO 8601\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `items` | array | Array of gist objects from GitHub API |
|
||||
| ↳ `id` | string | Gist ID |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `description` | string | Description |
|
||||
| ↳ `public` | boolean | Is public |
|
||||
| ↳ `files` | object | Files |
|
||||
| ↳ `owner` | object | Owner |
|
||||
| `count` | number | Number of gists returned |
|
||||
|
||||
### `github_update_gist`
|
||||
|
||||
Update a gist description or files. To delete a file, set its value to null in files object
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID to update |
|
||||
| `description` | string | No | New description for the gist |
|
||||
| `files` | json | No | JSON object with filenames as keys. Set to null to delete, or provide content to update/add |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Gist ID |
|
||||
| `html_url` | string | Web URL |
|
||||
| `description` | string | Description |
|
||||
| `public` | boolean | Is public |
|
||||
| `updated_at` | string | Update date |
|
||||
| `files` | object | Current files |
|
||||
|
||||
### `github_delete_gist`
|
||||
|
||||
Delete a gist by ID
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID to delete |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether deletion succeeded |
|
||||
| `gist_id` | string | The deleted gist ID |
|
||||
|
||||
### `github_fork_gist`
|
||||
|
||||
Fork a gist to create your own copy
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID to fork |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | New gist ID |
|
||||
| `html_url` | string | Web URL |
|
||||
| `description` | string | Description |
|
||||
| `public` | boolean | Is public |
|
||||
| `created_at` | string | Creation date |
|
||||
| `owner` | object | Owner info |
|
||||
| `files` | object | Files |
|
||||
|
||||
### `github_star_gist`
|
||||
|
||||
Star a gist
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID to star |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `starred` | boolean | Whether starring succeeded |
|
||||
| `gist_id` | string | The gist ID |
|
||||
|
||||
### `github_unstar_gist`
|
||||
|
||||
Unstar a gist
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `gist_id` | string | Yes | The gist ID to unstar |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `unstarred` | boolean | Whether unstarring succeeded |
|
||||
| `gist_id` | string | The gist ID |
|
||||
|
||||
### `github_fork_repo`
|
||||
|
||||
Fork a repository to your account or an organization
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner to fork from |
|
||||
| `repo` | string | Yes | Repository name to fork |
|
||||
| `organization` | string | No | Organization to fork into \(omit to fork to your account\) |
|
||||
| `name` | string | No | Custom name for the forked repository |
|
||||
| `default_branch_only` | boolean | No | Only fork the default branch \(default: false\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Repository ID |
|
||||
| `full_name` | string | Full name |
|
||||
| `html_url` | string | Web URL |
|
||||
| `clone_url` | string | Clone URL |
|
||||
| `ssh_url` | string | SSH URL |
|
||||
| `default_branch` | string | Default branch |
|
||||
| `fork` | boolean | Is a fork |
|
||||
| `parent` | object | Parent repository |
|
||||
| `owner` | object | Owner |
|
||||
|
||||
### `github_list_forks`
|
||||
|
||||
List forks of a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `sort` | string | No | Sort by: newest, oldest, stargazers, watchers \(default: newest\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `items` | array | Array of fork repository objects from GitHub API |
|
||||
| ↳ `id` | number | Repository ID |
|
||||
| ↳ `full_name` | string | Full name |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `owner` | object | Owner |
|
||||
| ↳ `stargazers_count` | number | Stars |
|
||||
| ↳ `forks_count` | number | Forks |
|
||||
| `count` | number | Number of forks returned |
|
||||
|
||||
### `github_create_milestone`
|
||||
|
||||
Create a milestone in a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `title` | string | Yes | Milestone title |
|
||||
| `state` | string | No | State: open or closed \(default: open\) |
|
||||
| `description` | string | No | Milestone description |
|
||||
| `due_on` | string | No | Due date \(ISO 8601 format, e.g., 2024-12-31T23:59:59Z\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `number` | number | Milestone number |
|
||||
| `title` | string | Title |
|
||||
| `description` | string | Description |
|
||||
| `state` | string | State |
|
||||
| `html_url` | string | Web URL |
|
||||
| `due_on` | string | Due date |
|
||||
| `open_issues` | number | Open issues |
|
||||
| `closed_issues` | number | Closed issues |
|
||||
| `creator` | object | Creator |
|
||||
|
||||
### `github_get_milestone`
|
||||
|
||||
Get a specific milestone by number
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `milestone_number` | number | Yes | Milestone number |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `number` | number | Milestone number |
|
||||
| `title` | string | Title |
|
||||
| `description` | string | Description |
|
||||
| `state` | string | State |
|
||||
| `html_url` | string | Web URL |
|
||||
| `due_on` | string | Due date |
|
||||
| `open_issues` | number | Open issues |
|
||||
| `closed_issues` | number | Closed issues |
|
||||
| `closed_at` | string | Close date |
|
||||
| `creator` | object | Creator |
|
||||
|
||||
### `github_list_milestones`
|
||||
|
||||
List milestones in a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `state` | string | No | Filter by state: open, closed, all \(default: open\) |
|
||||
| `sort` | string | No | Sort by: due_on or completeness \(default: due_on\) |
|
||||
| `direction` | string | No | Sort direction: asc or desc \(default: asc\) |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `items` | array | Array of milestone objects from GitHub API |
|
||||
| ↳ `number` | number | Milestone number |
|
||||
| ↳ `title` | string | Title |
|
||||
| ↳ `state` | string | State |
|
||||
| ↳ `html_url` | string | Web URL |
|
||||
| ↳ `open_issues` | number | Open issues |
|
||||
| ↳ `closed_issues` | number | Closed issues |
|
||||
| `count` | number | Number of milestones returned |
|
||||
|
||||
### `github_update_milestone`
|
||||
|
||||
Update a milestone in a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `milestone_number` | number | Yes | Milestone number to update |
|
||||
| `title` | string | No | New milestone title |
|
||||
| `state` | string | No | New state: open or closed |
|
||||
| `description` | string | No | New description |
|
||||
| `due_on` | string | No | New due date \(ISO 8601 format\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `number` | number | Milestone number |
|
||||
| `title` | string | Title |
|
||||
| `description` | string | Description |
|
||||
| `state` | string | State |
|
||||
| `html_url` | string | Web URL |
|
||||
| `due_on` | string | Due date |
|
||||
| `open_issues` | number | Open issues |
|
||||
| `closed_issues` | number | Closed issues |
|
||||
|
||||
### `github_delete_milestone`
|
||||
|
||||
Delete a milestone from a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `milestone_number` | number | Yes | Milestone number to delete |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether deletion succeeded |
|
||||
| `milestone_number` | number | The deleted milestone number |
|
||||
|
||||
### `github_create_issue_reaction`
|
||||
|
||||
Add a reaction to an issue
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `issue_number` | number | Yes | Issue number |
|
||||
| `content` | string | Yes | Reaction type: +1 \(thumbs up\), -1 \(thumbs down\), laugh, confused, heart, hooray, rocket, eyes |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Reaction ID |
|
||||
| `user` | object | User who reacted |
|
||||
| `content` | string | Reaction type |
|
||||
| `created_at` | string | Creation date |
|
||||
|
||||
### `github_delete_issue_reaction`
|
||||
|
||||
Remove a reaction from an issue
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `issue_number` | number | Yes | Issue number |
|
||||
| `reaction_id` | number | Yes | Reaction ID to delete |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether deletion succeeded |
|
||||
| `reaction_id` | number | The deleted reaction ID |
|
||||
|
||||
### `github_create_comment_reaction`
|
||||
|
||||
Add a reaction to an issue comment
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `comment_id` | number | Yes | Comment ID |
|
||||
| `content` | string | Yes | Reaction type: +1 \(thumbs up\), -1 \(thumbs down\), laugh, confused, heart, hooray, rocket, eyes |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | number | Reaction ID |
|
||||
| `user` | object | User who reacted |
|
||||
| `content` | string | Reaction type |
|
||||
| `created_at` | string | Creation date |
|
||||
|
||||
### `github_delete_comment_reaction`
|
||||
|
||||
Remove a reaction from an issue comment
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `comment_id` | number | Yes | Comment ID |
|
||||
| `reaction_id` | number | Yes | Reaction ID to delete |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether deletion succeeded |
|
||||
| `reaction_id` | number | The deleted reaction ID |
|
||||
|
||||
### `github_star_repo`
|
||||
|
||||
Star a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `starred` | boolean | Whether starring succeeded |
|
||||
| `owner` | string | Repository owner |
|
||||
| `repo` | string | Repository name |
|
||||
|
||||
### `github_unstar_repo`
|
||||
|
||||
Remove star from a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `unstarred` | boolean | Whether unstarring succeeded |
|
||||
| `owner` | string | Repository owner |
|
||||
| `repo` | string | Repository name |
|
||||
|
||||
### `github_check_star`
|
||||
|
||||
Check if you have starred a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `starred` | boolean | Whether you have starred the repo |
|
||||
| `owner` | string | Repository owner |
|
||||
| `repo` | string | Repository name |
|
||||
|
||||
### `github_list_stargazers`
|
||||
|
||||
List users who have starred a repository
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `owner` | string | Yes | Repository owner |
|
||||
| `repo` | string | Yes | Repository name |
|
||||
| `per_page` | number | No | Results per page \(max 100, default: 30\) |
|
||||
| `page` | number | No | Page number \(default: 1\) |
|
||||
| `apiKey` | string | Yes | GitHub API token |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `items` | array | Array of user objects from GitHub API |
|
||||
| ↳ `login` | string | Username |
|
||||
| ↳ `id` | number | User ID |
|
||||
| ↳ `avatar_url` | string | Avatar URL |
|
||||
| ↳ `html_url` | string | Profile URL |
|
||||
| ↳ `type` | string | User or Organization |
|
||||
| `count` | number | Number of stargazers returned |
|
||||
|
||||
|
||||
|
||||
@@ -119,6 +119,145 @@ Get a specific event from Google Calendar. Returns API-aligned fields only.
|
||||
| `creator` | json | Event creator |
|
||||
| `organizer` | json | Event organizer |
|
||||
|
||||
### `google_calendar_update`
|
||||
|
||||
Update an existing event in Google Calendar. Returns API-aligned fields only.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
|
||||
| `eventId` | string | Yes | Event ID to update |
|
||||
| `summary` | string | No | New event title/summary |
|
||||
| `description` | string | No | New event description |
|
||||
| `location` | string | No | New event location |
|
||||
| `startDateTime` | string | No | New start date and time. MUST include timezone offset \(e.g., 2025-06-03T10:00:00-08:00\) OR provide timeZone parameter |
|
||||
| `endDateTime` | string | No | New end date and time. MUST include timezone offset \(e.g., 2025-06-03T11:00:00-08:00\) OR provide timeZone parameter |
|
||||
| `timeZone` | string | No | Time zone \(e.g., America/Los_Angeles\). Required if datetime does not include offset. |
|
||||
| `attendees` | array | No | Array of attendee email addresses \(replaces existing attendees\) |
|
||||
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Event ID |
|
||||
| `htmlLink` | string | Event link |
|
||||
| `status` | string | Event status |
|
||||
| `summary` | string | Event title |
|
||||
| `description` | string | Event description |
|
||||
| `location` | string | Event location |
|
||||
| `start` | json | Event start |
|
||||
| `end` | json | Event end |
|
||||
| `attendees` | json | Event attendees |
|
||||
| `creator` | json | Event creator |
|
||||
| `organizer` | json | Event organizer |
|
||||
|
||||
### `google_calendar_delete`
|
||||
|
||||
Delete an event from Google Calendar. Returns API-aligned fields only.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
|
||||
| `eventId` | string | Yes | Event ID to delete |
|
||||
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `eventId` | string | Deleted event ID |
|
||||
| `deleted` | boolean | Whether deletion was successful |
|
||||
|
||||
### `google_calendar_move`
|
||||
|
||||
Move an event to a different calendar. Returns API-aligned fields only.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `calendarId` | string | No | Source calendar ID \(defaults to primary\) |
|
||||
| `eventId` | string | Yes | Event ID to move |
|
||||
| `destinationCalendarId` | string | Yes | Destination calendar ID |
|
||||
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Event ID |
|
||||
| `htmlLink` | string | Event link |
|
||||
| `status` | string | Event status |
|
||||
| `summary` | string | Event title |
|
||||
| `description` | string | Event description |
|
||||
| `location` | string | Event location |
|
||||
| `start` | json | Event start |
|
||||
| `end` | json | Event end |
|
||||
| `attendees` | json | Event attendees |
|
||||
| `creator` | json | Event creator |
|
||||
| `organizer` | json | Event organizer |
|
||||
|
||||
### `google_calendar_instances`
|
||||
|
||||
Get instances of a recurring event from Google Calendar. Returns API-aligned fields only.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
|
||||
| `eventId` | string | Yes | Recurring event ID to get instances of |
|
||||
| `timeMin` | string | No | Lower bound for instances \(RFC3339 timestamp, e.g., 2025-06-03T00:00:00Z\) |
|
||||
| `timeMax` | string | No | Upper bound for instances \(RFC3339 timestamp, e.g., 2025-06-04T00:00:00Z\) |
|
||||
| `maxResults` | number | No | Maximum number of instances to return \(default 250, max 2500\) |
|
||||
| `pageToken` | string | No | Token for retrieving subsequent pages of results |
|
||||
| `showDeleted` | boolean | No | Include deleted instances |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `nextPageToken` | string | Next page token |
|
||||
| `timeZone` | string | Calendar time zone |
|
||||
| `instances` | json | List of recurring event instances |
|
||||
|
||||
### `google_calendar_list_calendars`
|
||||
|
||||
List all calendars in the user
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `minAccessRole` | string | No | Minimum access role for returned calendars: freeBusyReader, reader, writer, or owner |
|
||||
| `maxResults` | number | No | Maximum number of calendars to return \(default 100, max 250\) |
|
||||
| `pageToken` | string | No | Token for retrieving subsequent pages of results |
|
||||
| `showDeleted` | boolean | No | Include deleted calendars |
|
||||
| `showHidden` | boolean | No | Include hidden calendars |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `nextPageToken` | string | Next page token |
|
||||
| `calendars` | array | List of calendars |
|
||||
| ↳ `id` | string | Calendar ID |
|
||||
| ↳ `summary` | string | Calendar title |
|
||||
| ↳ `description` | string | Calendar description |
|
||||
| ↳ `location` | string | Calendar location |
|
||||
| ↳ `timeZone` | string | Calendar time zone |
|
||||
| ↳ `accessRole` | string | Access role for the calendar |
|
||||
| ↳ `backgroundColor` | string | Calendar background color |
|
||||
| ↳ `foregroundColor` | string | Calendar foreground color |
|
||||
| ↳ `primary` | boolean | Whether this is the primary calendar |
|
||||
| ↳ `hidden` | boolean | Whether the calendar is hidden |
|
||||
| ↳ `selected` | boolean | Whether the calendar is selected |
|
||||
|
||||
### `google_calendar_quick_add`
|
||||
|
||||
Create events from natural language text. Returns API-aligned fields only.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Google Drive
|
||||
description: Create, upload, and list files
|
||||
description: Manage files, folders, and permissions
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
@@ -40,12 +40,178 @@ In Sim, the Google Drive integration enables your agents to interact directly wi
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Google Drive into the workflow. Can create, upload, and list files.
|
||||
Integrate Google Drive into the workflow. Can create, upload, download, copy, move, delete, share files and manage permissions.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `google_drive_list`
|
||||
|
||||
List files and folders in Google Drive with complete metadata
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `folderSelector` | string | No | Select the folder to list files from |
|
||||
| `folderId` | string | No | The ID of the folder to list files from \(internal use\) |
|
||||
| `query` | string | No | Search term to filter files by name \(e.g. "budget" finds files with "budget" in the name\). Do NOT use Google Drive query syntax here - just provide a plain search term. |
|
||||
| `pageSize` | number | No | The maximum number of files to return \(default: 100\) |
|
||||
| `pageToken` | string | No | The page token to use for pagination |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `files` | array | Array of file metadata objects from Google Drive |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `kind` | string | Resource type identifier |
|
||||
| ↳ `description` | string | File description |
|
||||
| ↳ `originalFilename` | string | Original uploaded filename |
|
||||
| ↳ `fullFileExtension` | string | Full file extension |
|
||||
| ↳ `fileExtension` | string | File extension |
|
||||
| ↳ `owners` | json | List of file owners |
|
||||
| ↳ `permissions` | json | File permissions |
|
||||
| ↳ `permissionIds` | json | Permission IDs |
|
||||
| ↳ `shared` | boolean | Whether file is shared |
|
||||
| ↳ `ownedByMe` | boolean | Whether owned by current user |
|
||||
| ↳ `writersCanShare` | boolean | Whether writers can share |
|
||||
| ↳ `viewersCanCopyContent` | boolean | Whether viewers can copy |
|
||||
| ↳ `copyRequiresWriterPermission` | boolean | Whether copy requires writer permission |
|
||||
| ↳ `sharingUser` | json | User who shared the file |
|
||||
| ↳ `starred` | boolean | Whether file is starred |
|
||||
| ↳ `trashed` | boolean | Whether file is in trash |
|
||||
| ↳ `explicitlyTrashed` | boolean | Whether explicitly trashed |
|
||||
| ↳ `appProperties` | json | App-specific properties |
|
||||
| ↳ `createdTime` | string | File creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `modifiedByMeTime` | string | When modified by current user |
|
||||
| ↳ `viewedByMeTime` | string | When last viewed by current user |
|
||||
| ↳ `sharedWithMeTime` | string | When shared with current user |
|
||||
| ↳ `lastModifyingUser` | json | User who last modified the file |
|
||||
| ↳ `viewedByMe` | boolean | Whether viewed by current user |
|
||||
| ↳ `modifiedByMe` | boolean | Whether modified by current user |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `webContentLink` | string | Direct download URL |
|
||||
| ↳ `iconLink` | string | URL to file icon |
|
||||
| ↳ `thumbnailLink` | string | URL to thumbnail |
|
||||
| ↳ `exportLinks` | json | Export format links |
|
||||
| ↳ `size` | string | File size in bytes |
|
||||
| ↳ `quotaBytesUsed` | string | Storage quota used |
|
||||
| ↳ `md5Checksum` | string | MD5 hash |
|
||||
| ↳ `sha1Checksum` | string | SHA-1 hash |
|
||||
| ↳ `sha256Checksum` | string | SHA-256 hash |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `spaces` | json | Spaces containing file |
|
||||
| ↳ `driveId` | string | Shared drive ID |
|
||||
| ↳ `capabilities` | json | User capabilities on file |
|
||||
| ↳ `version` | string | Version number |
|
||||
| ↳ `headRevisionId` | string | Head revision ID |
|
||||
| ↳ `hasThumbnail` | boolean | Whether has thumbnail |
|
||||
| ↳ `thumbnailVersion` | string | Thumbnail version |
|
||||
| ↳ `imageMediaMetadata` | json | Image-specific metadata |
|
||||
| ↳ `videoMediaMetadata` | json | Video-specific metadata |
|
||||
| ↳ `isAppAuthorized` | boolean | Whether created by requesting app |
|
||||
| ↳ `contentRestrictions` | json | Content restrictions |
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
| `nextPageToken` | string | Token for fetching the next page of results |
|
||||
|
||||
### `google_drive_get_file`
|
||||
|
||||
Get metadata for a specific file in Google Drive by its ID
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | json | The file metadata |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `description` | string | File description |
|
||||
| ↳ `size` | string | File size in bytes |
|
||||
| ↳ `starred` | boolean | Whether file is starred |
|
||||
| ↳ `trashed` | boolean | Whether file is in trash |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `webContentLink` | string | Direct download URL |
|
||||
| ↳ `iconLink` | string | URL to file icon |
|
||||
| ↳ `thumbnailLink` | string | URL to thumbnail |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `owners` | json | List of file owners |
|
||||
| ↳ `permissions` | json | File permissions |
|
||||
| ↳ `createdTime` | string | File creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `lastModifyingUser` | json | User who last modified the file |
|
||||
| ↳ `shared` | boolean | Whether file is shared |
|
||||
| ↳ `ownedByMe` | boolean | Whether owned by current user |
|
||||
| ↳ `capabilities` | json | User capabilities on file |
|
||||
| ↳ `md5Checksum` | string | MD5 hash |
|
||||
| ↳ `version` | string | Version number |
|
||||
|
||||
### `google_drive_create_folder`
|
||||
|
||||
Create a new folder in Google Drive with complete metadata returned
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileName` | string | Yes | Name of the folder to create |
|
||||
| `folderSelector` | string | No | Select the parent folder to create the folder in |
|
||||
| `folderId` | string | No | ID of the parent folder \(internal use\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | object | Complete created folder metadata from Google Drive |
|
||||
| ↳ `id` | string | Google Drive folder ID |
|
||||
| ↳ `name` | string | Folder name |
|
||||
| ↳ `mimeType` | string | MIME type \(application/vnd.google-apps.folder\) |
|
||||
| ↳ `kind` | string | Resource type identifier |
|
||||
| ↳ `description` | string | Folder description |
|
||||
| ↳ `owners` | json | List of folder owners |
|
||||
| ↳ `permissions` | json | Folder permissions |
|
||||
| ↳ `permissionIds` | json | Permission IDs |
|
||||
| ↳ `shared` | boolean | Whether folder is shared |
|
||||
| ↳ `ownedByMe` | boolean | Whether owned by current user |
|
||||
| ↳ `writersCanShare` | boolean | Whether writers can share |
|
||||
| ↳ `viewersCanCopyContent` | boolean | Whether viewers can copy |
|
||||
| ↳ `copyRequiresWriterPermission` | boolean | Whether copy requires writer permission |
|
||||
| ↳ `sharingUser` | json | User who shared the folder |
|
||||
| ↳ `starred` | boolean | Whether folder is starred |
|
||||
| ↳ `trashed` | boolean | Whether folder is in trash |
|
||||
| ↳ `explicitlyTrashed` | boolean | Whether explicitly trashed |
|
||||
| ↳ `appProperties` | json | App-specific properties |
|
||||
| ↳ `folderColorRgb` | string | Folder color |
|
||||
| ↳ `createdTime` | string | Folder creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `modifiedByMeTime` | string | When modified by current user |
|
||||
| ↳ `viewedByMeTime` | string | When last viewed by current user |
|
||||
| ↳ `sharedWithMeTime` | string | When shared with current user |
|
||||
| ↳ `lastModifyingUser` | json | User who last modified the folder |
|
||||
| ↳ `viewedByMe` | boolean | Whether viewed by current user |
|
||||
| ↳ `modifiedByMe` | boolean | Whether modified by current user |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `iconLink` | string | URL to folder icon |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `spaces` | json | Spaces containing folder |
|
||||
| ↳ `driveId` | string | Shared drive ID |
|
||||
| ↳ `capabilities` | json | User capabilities on folder |
|
||||
| ↳ `version` | string | Version number |
|
||||
| ↳ `isAppAuthorized` | boolean | Whether created by requesting app |
|
||||
| ↳ `contentRestrictions` | json | Content restrictions |
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
|
||||
### `google_drive_upload`
|
||||
|
||||
Upload a file to Google Drive with complete metadata returned
|
||||
@@ -119,61 +285,6 @@ Upload a file to Google Drive with complete metadata returned
|
||||
| ↳ `contentRestrictions` | json | Content restrictions |
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
|
||||
### `google_drive_create_folder`
|
||||
|
||||
Create a new folder in Google Drive with complete metadata returned
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileName` | string | Yes | Name of the folder to create |
|
||||
| `folderSelector` | string | No | Select the parent folder to create the folder in |
|
||||
| `folderId` | string | No | ID of the parent folder \(internal use\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | object | Complete created folder metadata from Google Drive |
|
||||
| ↳ `id` | string | Google Drive folder ID |
|
||||
| ↳ `name` | string | Folder name |
|
||||
| ↳ `mimeType` | string | MIME type \(application/vnd.google-apps.folder\) |
|
||||
| ↳ `kind` | string | Resource type identifier |
|
||||
| ↳ `description` | string | Folder description |
|
||||
| ↳ `owners` | json | List of folder owners |
|
||||
| ↳ `permissions` | json | Folder permissions |
|
||||
| ↳ `permissionIds` | json | Permission IDs |
|
||||
| ↳ `shared` | boolean | Whether folder is shared |
|
||||
| ↳ `ownedByMe` | boolean | Whether owned by current user |
|
||||
| ↳ `writersCanShare` | boolean | Whether writers can share |
|
||||
| ↳ `viewersCanCopyContent` | boolean | Whether viewers can copy |
|
||||
| ↳ `copyRequiresWriterPermission` | boolean | Whether copy requires writer permission |
|
||||
| ↳ `sharingUser` | json | User who shared the folder |
|
||||
| ↳ `starred` | boolean | Whether folder is starred |
|
||||
| ↳ `trashed` | boolean | Whether folder is in trash |
|
||||
| ↳ `explicitlyTrashed` | boolean | Whether explicitly trashed |
|
||||
| ↳ `appProperties` | json | App-specific properties |
|
||||
| ↳ `folderColorRgb` | string | Folder color |
|
||||
| ↳ `createdTime` | string | Folder creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `modifiedByMeTime` | string | When modified by current user |
|
||||
| ↳ `viewedByMeTime` | string | When last viewed by current user |
|
||||
| ↳ `sharedWithMeTime` | string | When shared with current user |
|
||||
| ↳ `lastModifyingUser` | json | User who last modified the folder |
|
||||
| ↳ `viewedByMe` | boolean | Whether viewed by current user |
|
||||
| ↳ `modifiedByMe` | boolean | Whether modified by current user |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `iconLink` | string | URL to folder icon |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `spaces` | json | Spaces containing folder |
|
||||
| ↳ `driveId` | string | Shared drive ID |
|
||||
| ↳ `capabilities` | json | User capabilities on folder |
|
||||
| ↳ `version` | string | Version number |
|
||||
| ↳ `isAppAuthorized` | boolean | Whether created by requesting app |
|
||||
| ↳ `contentRestrictions` | json | Content restrictions |
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
|
||||
### `google_drive_download`
|
||||
|
||||
Download a file from Google Drive with complete metadata (exports Google Workspace files automatically)
|
||||
@@ -251,77 +362,229 @@ Download a file from Google Drive with complete metadata (exports Google Workspa
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
| ↳ `revisions` | json | File revision history \(first 100 revisions only\) |
|
||||
|
||||
### `google_drive_list`
|
||||
### `google_drive_copy`
|
||||
|
||||
List files and folders in Google Drive with complete metadata
|
||||
Create a copy of a file in Google Drive
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `folderSelector` | string | No | Select the folder to list files from |
|
||||
| `folderId` | string | No | The ID of the folder to list files from \(internal use\) |
|
||||
| `query` | string | No | Search term to filter files by name \(e.g. "budget" finds files with "budget" in the name\). Do NOT use Google Drive query syntax here - just provide a plain search term. |
|
||||
| `pageSize` | number | No | The maximum number of files to return \(default: 100\) |
|
||||
| `pageToken` | string | No | The page token to use for pagination |
|
||||
| `fileId` | string | Yes | The ID of the file to copy |
|
||||
| `newName` | string | No | Name for the copied file \(defaults to "Copy of \[original name\]"\) |
|
||||
| `destinationFolderId` | string | No | ID of the folder to place the copy in \(defaults to same location as original\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `files` | array | Array of file metadata objects from Google Drive |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `kind` | string | Resource type identifier |
|
||||
| ↳ `description` | string | File description |
|
||||
| ↳ `originalFilename` | string | Original uploaded filename |
|
||||
| ↳ `fullFileExtension` | string | Full file extension |
|
||||
| ↳ `fileExtension` | string | File extension |
|
||||
| ↳ `owners` | json | List of file owners |
|
||||
| ↳ `permissions` | json | File permissions |
|
||||
| ↳ `permissionIds` | json | Permission IDs |
|
||||
| ↳ `shared` | boolean | Whether file is shared |
|
||||
| ↳ `ownedByMe` | boolean | Whether owned by current user |
|
||||
| ↳ `writersCanShare` | boolean | Whether writers can share |
|
||||
| ↳ `viewersCanCopyContent` | boolean | Whether viewers can copy |
|
||||
| ↳ `copyRequiresWriterPermission` | boolean | Whether copy requires writer permission |
|
||||
| ↳ `sharingUser` | json | User who shared the file |
|
||||
| ↳ `starred` | boolean | Whether file is starred |
|
||||
| ↳ `trashed` | boolean | Whether file is in trash |
|
||||
| ↳ `explicitlyTrashed` | boolean | Whether explicitly trashed |
|
||||
| ↳ `appProperties` | json | App-specific properties |
|
||||
| ↳ `createdTime` | string | File creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `modifiedByMeTime` | string | When modified by current user |
|
||||
| ↳ `viewedByMeTime` | string | When last viewed by current user |
|
||||
| ↳ `sharedWithMeTime` | string | When shared with current user |
|
||||
| ↳ `lastModifyingUser` | json | User who last modified the file |
|
||||
| ↳ `viewedByMe` | boolean | Whether viewed by current user |
|
||||
| ↳ `modifiedByMe` | boolean | Whether modified by current user |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `webContentLink` | string | Direct download URL |
|
||||
| ↳ `iconLink` | string | URL to file icon |
|
||||
| ↳ `thumbnailLink` | string | URL to thumbnail |
|
||||
| ↳ `exportLinks` | json | Export format links |
|
||||
| ↳ `size` | string | File size in bytes |
|
||||
| ↳ `quotaBytesUsed` | string | Storage quota used |
|
||||
| ↳ `md5Checksum` | string | MD5 hash |
|
||||
| ↳ `sha1Checksum` | string | SHA-1 hash |
|
||||
| ↳ `sha256Checksum` | string | SHA-256 hash |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `spaces` | json | Spaces containing file |
|
||||
| ↳ `driveId` | string | Shared drive ID |
|
||||
| ↳ `capabilities` | json | User capabilities on file |
|
||||
| ↳ `version` | string | Version number |
|
||||
| ↳ `headRevisionId` | string | Head revision ID |
|
||||
| ↳ `hasThumbnail` | boolean | Whether has thumbnail |
|
||||
| ↳ `thumbnailVersion` | string | Thumbnail version |
|
||||
| ↳ `imageMediaMetadata` | json | Image-specific metadata |
|
||||
| ↳ `videoMediaMetadata` | json | Video-specific metadata |
|
||||
| ↳ `isAppAuthorized` | boolean | Whether created by requesting app |
|
||||
| ↳ `contentRestrictions` | json | Content restrictions |
|
||||
| ↳ `linkShareMetadata` | json | Link share metadata |
|
||||
| `nextPageToken` | string | Token for fetching the next page of results |
|
||||
| `file` | json | The copied file metadata |
|
||||
| ↳ `id` | string | Google Drive file ID of the copy |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `createdTime` | string | File creation time |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
| ↳ `owners` | json | List of file owners |
|
||||
| ↳ `size` | string | File size in bytes |
|
||||
|
||||
### `google_drive_update`
|
||||
|
||||
Update file metadata in Google Drive (rename, move, star, add description)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to update |
|
||||
| `name` | string | No | New name for the file |
|
||||
| `description` | string | No | New description for the file |
|
||||
| `addParents` | string | No | Comma-separated list of parent folder IDs to add \(moves file to these folders\) |
|
||||
| `removeParents` | string | No | Comma-separated list of parent folder IDs to remove |
|
||||
| `starred` | boolean | No | Whether to star or unstar the file |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | json | The updated file metadata |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `description` | string | File description |
|
||||
| ↳ `starred` | boolean | Whether file is starred |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
| ↳ `modifiedTime` | string | Last modification time |
|
||||
|
||||
### `google_drive_trash`
|
||||
|
||||
Move a file to the trash in Google Drive (can be restored later)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to move to trash |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | json | The trashed file metadata |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `trashed` | boolean | Whether file is in trash \(should be true\) |
|
||||
| ↳ `trashedTime` | string | When file was trashed |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
|
||||
### `google_drive_untrash`
|
||||
|
||||
Restore a file from the trash in Google Drive
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to restore from trash |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `file` | json | The restored file metadata |
|
||||
| ↳ `id` | string | Google Drive file ID |
|
||||
| ↳ `name` | string | File name |
|
||||
| ↳ `mimeType` | string | MIME type |
|
||||
| ↳ `trashed` | boolean | Whether file is in trash \(should be false\) |
|
||||
| ↳ `webViewLink` | string | URL to view in browser |
|
||||
| ↳ `parents` | json | Parent folder IDs |
|
||||
|
||||
### `google_drive_delete`
|
||||
|
||||
Permanently delete a file from Google Drive (bypasses trash)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to permanently delete |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether the file was successfully deleted |
|
||||
| `fileId` | string | The ID of the deleted file |
|
||||
|
||||
### `google_drive_share`
|
||||
|
||||
Share a file with a user, group, domain, or make it public
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to share |
|
||||
| `type` | string | Yes | Type of grantee: user, group, domain, or anyone |
|
||||
| `role` | string | Yes | Permission role: owner \(transfer ownership\), organizer \(shared drive only\), fileOrganizer \(shared drive only\), writer \(edit\), commenter \(view and comment\), reader \(view only\) |
|
||||
| `email` | string | No | Email address of the user or group \(required for type=user or type=group\) |
|
||||
| `domain` | string | No | Domain to share with \(required for type=domain\) |
|
||||
| `transferOwnership` | boolean | No | Required when role is owner. Transfers ownership to the specified user. |
|
||||
| `moveToNewOwnersRoot` | boolean | No | When transferring ownership, move the file to the new owner's My Drive root folder. |
|
||||
| `sendNotification` | boolean | No | Whether to send an email notification \(default: true\) |
|
||||
| `emailMessage` | string | No | Custom message to include in the notification email |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `permission` | json | The created permission details |
|
||||
| ↳ `id` | string | Permission ID |
|
||||
| ↳ `type` | string | Grantee type \(user, group, domain, anyone\) |
|
||||
| ↳ `role` | string | Permission role |
|
||||
| ↳ `emailAddress` | string | Email of the grantee |
|
||||
| ↳ `displayName` | string | Display name of the grantee |
|
||||
| ↳ `domain` | string | Domain of the grantee |
|
||||
| ↳ `expirationTime` | string | Expiration time |
|
||||
| ↳ `deleted` | boolean | Whether grantee is deleted |
|
||||
|
||||
### `google_drive_unshare`
|
||||
|
||||
Remove a permission from a file (revoke access)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to modify permissions on |
|
||||
| `permissionId` | string | Yes | The ID of the permission to remove \(use list_permissions to find this\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `removed` | boolean | Whether the permission was successfully removed |
|
||||
| `fileId` | string | The ID of the file |
|
||||
| `permissionId` | string | The ID of the removed permission |
|
||||
|
||||
### `google_drive_list_permissions`
|
||||
|
||||
List all permissions (who has access) for a file in Google Drive
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileId` | string | Yes | The ID of the file to list permissions for |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `permissions` | array | List of permissions on the file |
|
||||
| ↳ `id` | string | Permission ID \(use to remove permission\) |
|
||||
| ↳ `type` | string | Grantee type \(user, group, domain, anyone\) |
|
||||
| ↳ `role` | string | Permission role \(owner, organizer, fileOrganizer, writer, commenter, reader\) |
|
||||
| ↳ `emailAddress` | string | Email of the grantee |
|
||||
| ↳ `displayName` | string | Display name of the grantee |
|
||||
| ↳ `photoLink` | string | Photo URL of the grantee |
|
||||
| ↳ `domain` | string | Domain of the grantee |
|
||||
| ↳ `expirationTime` | string | When permission expires |
|
||||
| ↳ `deleted` | boolean | Whether grantee account is deleted |
|
||||
| ↳ `allowFileDiscovery` | boolean | Whether file is discoverable by grantee |
|
||||
| ↳ `pendingOwner` | boolean | Whether ownership transfer is pending |
|
||||
| ↳ `permissionDetails` | json | Details about inherited permissions |
|
||||
|
||||
### `google_drive_get_about`
|
||||
|
||||
Get information about the user and their Google Drive (storage quota, capabilities)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `user` | json | Information about the authenticated user |
|
||||
| ↳ `displayName` | string | User display name |
|
||||
| ↳ `emailAddress` | string | User email address |
|
||||
| ↳ `photoLink` | string | URL to user profile photo |
|
||||
| ↳ `permissionId` | string | User permission ID |
|
||||
| ↳ `me` | boolean | Whether this is the authenticated user |
|
||||
| `storageQuota` | json | Storage quota information in bytes |
|
||||
| ↳ `limit` | string | Total storage limit in bytes \(null for unlimited\) |
|
||||
| ↳ `usage` | string | Total storage used in bytes |
|
||||
| ↳ `usageInDrive` | string | Storage used by Drive files in bytes |
|
||||
| ↳ `usageInDriveTrash` | string | Storage used by trashed files in bytes |
|
||||
| `canCreateDrives` | boolean | Whether user can create shared drives |
|
||||
| `importFormats` | json | Map of MIME types that can be imported and their target formats |
|
||||
| `exportFormats` | json | Map of Google Workspace MIME types and their exportable formats |
|
||||
| `maxUploadSize` | string | Maximum upload size in bytes |
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Google Forms
|
||||
description: Read responses from a Google Form
|
||||
description: Manage Google Forms and responses
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
@@ -29,7 +29,7 @@ In Sim, the Google Forms integration enables your agents to programmatically acc
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Google Forms into your workflow. Provide a Form ID to list responses, or specify a Response ID to fetch a single response. Requires OAuth.
|
||||
Integrate Google Forms into your workflow. Read form structure, get responses, create forms, update content, and manage notification watches.
|
||||
|
||||
|
||||
|
||||
@@ -37,15 +37,202 @@ Integrate Google Forms into your workflow. Provide a Form ID to list responses,
|
||||
|
||||
### `google_forms_get_responses`
|
||||
|
||||
Retrieve a single response or list responses from a Google Form
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form |
|
||||
| `responseId` | string | No | If provided, returns this specific response |
|
||||
| `pageSize` | number | No | Maximum number of responses to return \(service may return fewer\). Defaults to 5000. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `data` | json | Response or list of responses |
|
||||
| `response` | json | Operation response data |
|
||||
| `formId` | string | Form ID |
|
||||
| `title` | string | Form title |
|
||||
| `responderUri` | string | Form responder URL |
|
||||
| `items` | json | Form items |
|
||||
| `responses` | json | Form responses |
|
||||
| `watches` | json | Form watches |
|
||||
|
||||
### `google_forms_get_form`
|
||||
|
||||
Retrieve a form structure including its items, settings, and metadata
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `formId` | string | The form ID |
|
||||
| `title` | string | The form title visible to responders |
|
||||
| `description` | string | The form description |
|
||||
| `documentTitle` | string | The document title visible in Drive |
|
||||
| `responderUri` | string | The URI to share with responders |
|
||||
| `linkedSheetId` | string | The ID of the linked Google Sheet |
|
||||
| `revisionId` | string | The revision ID of the form |
|
||||
| `items` | array | The form items \(questions, sections, etc.\) |
|
||||
| ↳ `itemId` | string | Item ID |
|
||||
| ↳ `title` | string | Item title |
|
||||
| ↳ `description` | string | Item description |
|
||||
| `settings` | json | Form settings |
|
||||
| `publishSettings` | json | Form publish settings |
|
||||
|
||||
### `google_forms_create_form`
|
||||
|
||||
Create a new Google Form with a title
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `title` | string | Yes | The title of the form visible to responders |
|
||||
| `documentTitle` | string | No | The document title visible in Drive \(defaults to form title\) |
|
||||
| `unpublished` | boolean | No | If true, create an unpublished form that does not accept responses |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `formId` | string | The ID of the created form |
|
||||
| `title` | string | The form title |
|
||||
| `documentTitle` | string | The document title in Drive |
|
||||
| `responderUri` | string | The URI to share with responders |
|
||||
| `revisionId` | string | The revision ID of the form |
|
||||
|
||||
### `google_forms_batch_update`
|
||||
|
||||
Apply multiple updates to a form (add items, update info, change settings, etc.)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form to update |
|
||||
| `requests` | json | Yes | Array of update requests \(updateFormInfo, updateSettings, createItem, updateItem, moveItem, deleteItem\) |
|
||||
| `includeFormInResponse` | boolean | No | Whether to return the updated form in the response |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `replies` | array | The replies from each update request |
|
||||
| `writeControl` | json | Write control information with revision IDs |
|
||||
| `form` | json | The updated form \(if includeFormInResponse was true\) |
|
||||
|
||||
### `google_forms_set_publish_settings`
|
||||
|
||||
Update the publish settings of a form (publish/unpublish, accept responses)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form |
|
||||
| `isPublished` | boolean | Yes | Whether the form is published and visible to others |
|
||||
| `isAcceptingResponses` | boolean | No | Whether the form accepts responses \(forced to false if isPublished is false\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `formId` | string | The form ID |
|
||||
| `publishSettings` | json | The updated publish settings |
|
||||
| ↳ `publishState` | object | The publish state |
|
||||
| ↳ `isPublished` | boolean | Whether the form is published |
|
||||
| ↳ `isAcceptingResponses` | boolean | Whether the form accepts responses |
|
||||
| ↳ `isPublished` | boolean | Whether the form is published |
|
||||
| ↳ `isAcceptingResponses` | boolean | Whether the form accepts responses |
|
||||
|
||||
### `google_forms_create_watch`
|
||||
|
||||
Create a notification watch for form changes (schema changes or new responses)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form to watch |
|
||||
| `eventType` | string | Yes | Event type to watch: SCHEMA \(form changes\) or RESPONSES \(new submissions\) |
|
||||
| `topicName` | string | Yes | The Cloud Pub/Sub topic name \(format: projects/\{project\}/topics/\{topic\}\) |
|
||||
| `watchId` | string | No | Custom watch ID \(4-63 chars, lowercase letters, numbers, hyphens\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | The watch ID |
|
||||
| `eventType` | string | The event type being watched |
|
||||
| `topicName` | string | The Cloud Pub/Sub topic |
|
||||
| `createTime` | string | When the watch was created |
|
||||
| `expireTime` | string | When the watch expires \(7 days after creation\) |
|
||||
| `state` | string | The watch state \(ACTIVE, SUSPENDED\) |
|
||||
|
||||
### `google_forms_list_watches`
|
||||
|
||||
List all notification watches for a form
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `watches` | array | List of watches for the form |
|
||||
| ↳ `id` | string | Watch ID |
|
||||
| ↳ `eventType` | string | Event type \(SCHEMA or RESPONSES\) |
|
||||
| ↳ `createTime` | string | When the watch was created |
|
||||
| ↳ `expireTime` | string | When the watch expires |
|
||||
| ↳ `state` | string | Watch state |
|
||||
|
||||
### `google_forms_delete_watch`
|
||||
|
||||
Delete a notification watch from a form
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form |
|
||||
| `watchId` | string | Yes | The ID of the watch to delete |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether the watch was successfully deleted |
|
||||
|
||||
### `google_forms_renew_watch`
|
||||
|
||||
Renew a notification watch for another 7 days
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `formId` | string | Yes | The ID of the Google Form |
|
||||
| `watchId` | string | Yes | The ID of the watch to renew |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | The watch ID |
|
||||
| `eventType` | string | The event type being watched |
|
||||
| `expireTime` | string | The new expiration time |
|
||||
| `state` | string | The watch state |
|
||||
|
||||
|
||||
|
||||
@@ -215,4 +215,191 @@ Check if a user is a member of a Google Group
|
||||
| --------- | ---- | ----------- |
|
||||
| `isMember` | boolean | Whether the user is a member of the group |
|
||||
|
||||
### `google_groups_list_aliases`
|
||||
|
||||
List all email aliases for a Google Group
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `groupKey` | string | Yes | Group email address or unique group ID |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `aliases` | array | List of email aliases for the group |
|
||||
| ↳ `id` | string | Unique group identifier |
|
||||
| ↳ `primaryEmail` | string | Group |
|
||||
| ↳ `alias` | string | Alias email address |
|
||||
| ↳ `kind` | string | API resource type |
|
||||
| ↳ `etag` | string | Resource version identifier |
|
||||
|
||||
### `google_groups_add_alias`
|
||||
|
||||
Add an email alias to a Google Group
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `groupKey` | string | Yes | Group email address or unique group ID |
|
||||
| `alias` | string | Yes | The email alias to add to the group |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `id` | string | Unique group identifier |
|
||||
| `primaryEmail` | string | Group |
|
||||
| `alias` | string | The alias that was added |
|
||||
| `kind` | string | API resource type |
|
||||
| `etag` | string | Resource version identifier |
|
||||
|
||||
### `google_groups_remove_alias`
|
||||
|
||||
Remove an email alias from a Google Group
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `groupKey` | string | Yes | Group email address or unique group ID |
|
||||
| `alias` | string | Yes | The email alias to remove from the group |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether the alias was successfully deleted |
|
||||
|
||||
### `google_groups_get_settings`
|
||||
|
||||
Get the settings for a Google Group including access permissions, moderation, and posting options
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `groupEmail` | string | Yes | The email address of the group |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `email` | string | The group |
|
||||
| `name` | string | The group name \(max 75 characters\) |
|
||||
| `description` | string | The group description \(max 4096 characters\) |
|
||||
| `whoCanJoin` | string | Who can join the group \(ANYONE_CAN_JOIN, ALL_IN_DOMAIN_CAN_JOIN, INVITED_CAN_JOIN, CAN_REQUEST_TO_JOIN\) |
|
||||
| `whoCanViewMembership` | string | Who can view group membership |
|
||||
| `whoCanViewGroup` | string | Who can view group messages |
|
||||
| `whoCanPostMessage` | string | Who can post messages to the group |
|
||||
| `allowExternalMembers` | string | Whether external users can be members |
|
||||
| `allowWebPosting` | string | Whether web posting is allowed |
|
||||
| `primaryLanguage` | string | The group |
|
||||
| `isArchived` | string | Whether messages are archived |
|
||||
| `archiveOnly` | string | Whether the group is archive-only \(inactive\) |
|
||||
| `messageModerationLevel` | string | Message moderation level |
|
||||
| `spamModerationLevel` | string | Spam handling level \(ALLOW, MODERATE, SILENTLY_MODERATE, REJECT\) |
|
||||
| `replyTo` | string | Default reply destination |
|
||||
| `customReplyTo` | string | Custom email for replies |
|
||||
| `includeCustomFooter` | string | Whether to include custom footer |
|
||||
| `customFooterText` | string | Custom footer text \(max 1000 characters\) |
|
||||
| `sendMessageDenyNotification` | string | Whether to send rejection notifications |
|
||||
| `defaultMessageDenyNotificationText` | string | Default rejection message text |
|
||||
| `membersCanPostAsTheGroup` | string | Whether members can post as the group |
|
||||
| `includeInGlobalAddressList` | string | Whether included in Global Address List |
|
||||
| `whoCanLeaveGroup` | string | Who can leave the group |
|
||||
| `whoCanContactOwner` | string | Who can contact the group owner |
|
||||
| `favoriteRepliesOnTop` | string | Whether favorite replies appear at top |
|
||||
| `whoCanApproveMembers` | string | Who can approve new members |
|
||||
| `whoCanBanUsers` | string | Who can ban users |
|
||||
| `whoCanModerateMembers` | string | Who can manage members |
|
||||
| `whoCanModerateContent` | string | Who can moderate content |
|
||||
| `whoCanAssistContent` | string | Who can assist with content metadata |
|
||||
| `enableCollaborativeInbox` | string | Whether collaborative inbox is enabled |
|
||||
| `whoCanDiscoverGroup` | string | Who can discover the group |
|
||||
| `defaultSender` | string | Default sender identity \(DEFAULT_SELF or GROUP\) |
|
||||
|
||||
### `google_groups_update_settings`
|
||||
|
||||
Update the settings for a Google Group including access permissions, moderation, and posting options
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `groupEmail` | string | Yes | The email address of the group |
|
||||
| `name` | string | No | The group name \(max 75 characters\) |
|
||||
| `description` | string | No | The group description \(max 4096 characters\) |
|
||||
| `whoCanJoin` | string | No | Who can join: ANYONE_CAN_JOIN, ALL_IN_DOMAIN_CAN_JOIN, INVITED_CAN_JOIN, CAN_REQUEST_TO_JOIN |
|
||||
| `whoCanViewMembership` | string | No | Who can view membership: ALL_IN_DOMAIN_CAN_VIEW, ALL_MEMBERS_CAN_VIEW, ALL_MANAGERS_CAN_VIEW |
|
||||
| `whoCanViewGroup` | string | No | Who can view group messages: ANYONE_CAN_VIEW, ALL_IN_DOMAIN_CAN_VIEW, ALL_MEMBERS_CAN_VIEW, ALL_MANAGERS_CAN_VIEW |
|
||||
| `whoCanPostMessage` | string | No | Who can post: NONE_CAN_POST, ALL_MANAGERS_CAN_POST, ALL_MEMBERS_CAN_POST, ALL_OWNERS_CAN_POST, ALL_IN_DOMAIN_CAN_POST, ANYONE_CAN_POST |
|
||||
| `allowExternalMembers` | string | No | Whether external users can be members: true or false |
|
||||
| `allowWebPosting` | string | No | Whether web posting is allowed: true or false |
|
||||
| `primaryLanguage` | string | No | The group's primary language \(e.g., en\) |
|
||||
| `isArchived` | string | No | Whether messages are archived: true or false |
|
||||
| `archiveOnly` | string | No | Whether the group is archive-only \(inactive\): true or false |
|
||||
| `messageModerationLevel` | string | No | Message moderation: MODERATE_ALL_MESSAGES, MODERATE_NON_MEMBERS, MODERATE_NEW_MEMBERS, MODERATE_NONE |
|
||||
| `spamModerationLevel` | string | No | Spam handling: ALLOW, MODERATE, SILENTLY_MODERATE, REJECT |
|
||||
| `replyTo` | string | No | Default reply: REPLY_TO_CUSTOM, REPLY_TO_SENDER, REPLY_TO_LIST, REPLY_TO_OWNER, REPLY_TO_IGNORE, REPLY_TO_MANAGERS |
|
||||
| `customReplyTo` | string | No | Custom email for replies \(when replyTo is REPLY_TO_CUSTOM\) |
|
||||
| `includeCustomFooter` | string | No | Whether to include custom footer: true or false |
|
||||
| `customFooterText` | string | No | Custom footer text \(max 1000 characters\) |
|
||||
| `sendMessageDenyNotification` | string | No | Whether to send rejection notifications: true or false |
|
||||
| `defaultMessageDenyNotificationText` | string | No | Default rejection message text |
|
||||
| `membersCanPostAsTheGroup` | string | No | Whether members can post as the group: true or false |
|
||||
| `includeInGlobalAddressList` | string | No | Whether included in Global Address List: true or false |
|
||||
| `whoCanLeaveGroup` | string | No | Who can leave: ALL_MANAGERS_CAN_LEAVE, ALL_MEMBERS_CAN_LEAVE, NONE_CAN_LEAVE |
|
||||
| `whoCanContactOwner` | string | No | Who can contact owner: ALL_IN_DOMAIN_CAN_CONTACT, ALL_MANAGERS_CAN_CONTACT, ALL_MEMBERS_CAN_CONTACT, ANYONE_CAN_CONTACT |
|
||||
| `favoriteRepliesOnTop` | string | No | Whether favorite replies appear at top: true or false |
|
||||
| `whoCanApproveMembers` | string | No | Who can approve members: ALL_OWNERS_CAN_APPROVE, ALL_MANAGERS_CAN_APPROVE, ALL_MEMBERS_CAN_APPROVE, NONE_CAN_APPROVE |
|
||||
| `whoCanBanUsers` | string | No | Who can ban users: OWNERS_ONLY, OWNERS_AND_MANAGERS, NONE |
|
||||
| `whoCanModerateMembers` | string | No | Who can manage members: OWNERS_ONLY, OWNERS_AND_MANAGERS, ALL_MEMBERS, NONE |
|
||||
| `whoCanModerateContent` | string | No | Who can moderate content: OWNERS_ONLY, OWNERS_AND_MANAGERS, ALL_MEMBERS, NONE |
|
||||
| `whoCanAssistContent` | string | No | Who can assist with content metadata: OWNERS_ONLY, OWNERS_AND_MANAGERS, ALL_MEMBERS, NONE |
|
||||
| `enableCollaborativeInbox` | string | No | Whether collaborative inbox is enabled: true or false |
|
||||
| `whoCanDiscoverGroup` | string | No | Who can discover: ANYONE_CAN_DISCOVER, ALL_IN_DOMAIN_CAN_DISCOVER, ALL_MEMBERS_CAN_DISCOVER |
|
||||
| `defaultSender` | string | No | Default sender: DEFAULT_SELF or GROUP |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `email` | string | The group |
|
||||
| `name` | string | The group name |
|
||||
| `description` | string | The group description |
|
||||
| `whoCanJoin` | string | Who can join the group |
|
||||
| `whoCanViewMembership` | string | Who can view group membership |
|
||||
| `whoCanViewGroup` | string | Who can view group messages |
|
||||
| `whoCanPostMessage` | string | Who can post messages to the group |
|
||||
| `allowExternalMembers` | string | Whether external users can be members |
|
||||
| `allowWebPosting` | string | Whether web posting is allowed |
|
||||
| `primaryLanguage` | string | The group |
|
||||
| `isArchived` | string | Whether messages are archived |
|
||||
| `archiveOnly` | string | Whether the group is archive-only |
|
||||
| `messageModerationLevel` | string | Message moderation level |
|
||||
| `spamModerationLevel` | string | Spam handling level |
|
||||
| `replyTo` | string | Default reply destination |
|
||||
| `customReplyTo` | string | Custom email for replies |
|
||||
| `includeCustomFooter` | string | Whether to include custom footer |
|
||||
| `customFooterText` | string | Custom footer text |
|
||||
| `sendMessageDenyNotification` | string | Whether to send rejection notifications |
|
||||
| `defaultMessageDenyNotificationText` | string | Default rejection message text |
|
||||
| `membersCanPostAsTheGroup` | string | Whether members can post as the group |
|
||||
| `includeInGlobalAddressList` | string | Whether included in Global Address List |
|
||||
| `whoCanLeaveGroup` | string | Who can leave the group |
|
||||
| `whoCanContactOwner` | string | Who can contact the group owner |
|
||||
| `favoriteRepliesOnTop` | string | Whether favorite replies appear at top |
|
||||
| `whoCanApproveMembers` | string | Who can approve new members |
|
||||
| `whoCanBanUsers` | string | Who can ban users |
|
||||
| `whoCanModerateMembers` | string | Who can manage members |
|
||||
| `whoCanModerateContent` | string | Who can moderate content |
|
||||
| `whoCanAssistContent` | string | Who can assist with content metadata |
|
||||
| `enableCollaborativeInbox` | string | Whether collaborative inbox is enabled |
|
||||
| `whoCanDiscoverGroup` | string | Who can discover the group |
|
||||
| `defaultSender` | string | Default sender identity |
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ In Sim, the Google Sheets integration empowers your agents to automate reading f
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Google Sheets into the workflow with explicit sheet selection. Can read, write, append, and update data in specific sheets.
|
||||
Integrate Google Sheets into the workflow with explicit sheet selection. Can read, write, append, update, clear data, create spreadsheets, get spreadsheet info, and copy sheets.
|
||||
|
||||
|
||||
|
||||
@@ -42,9 +42,8 @@ Read data from a specific sheet in a Google Sheets spreadsheet
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to read from |
|
||||
| `cellRange` | string | No | The cell range to read \(e.g. "A1:D10"\). Defaults to "A1:Z1000" if not specified. |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet \(found in the URL: docs.google.com/spreadsheets/d/\{SPREADSHEET_ID\}/edit\). |
|
||||
| `range` | string | No | The A1 notation range to read \(e.g. "Sheet1!A1:D10", "A1:B5"\). Defaults to first sheet A1:Z1000 if not specified. |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -66,8 +65,7 @@ Write data to a specific sheet in a Google Sheets spreadsheet
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to write to |
|
||||
| `cellRange` | string | No | The cell range to write to \(e.g. "A1:D10", "A1"\). Defaults to "A1" if not specified. |
|
||||
| `range` | string | No | The A1 notation range to write to \(e.g. "Sheet1!A1:D10", "A1:B5"\) |
|
||||
| `values` | array | Yes | The data to write as a 2D array \(e.g. \[\["Name", "Age"\], \["Alice", 30\], \["Bob", 25\]\]\) or array of objects. |
|
||||
| `valueInputOption` | string | No | The format of the data to write |
|
||||
| `includeValuesInResponse` | boolean | No | Whether to include the written values in the response |
|
||||
@@ -93,8 +91,7 @@ Update data in a specific sheet in a Google Sheets spreadsheet
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to update |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to update |
|
||||
| `cellRange` | string | No | The cell range to update \(e.g. "A1:D10", "A1"\). Defaults to "A1" if not specified. |
|
||||
| `range` | string | No | The A1 notation range to update \(e.g. "Sheet1!A1:D10", "A1:B5"\) |
|
||||
| `values` | array | Yes | The data to update as a 2D array \(e.g. \[\["Name", "Age"\], \["Alice", 30\]\]\) or array of objects. |
|
||||
| `valueInputOption` | string | No | The format of the data to update |
|
||||
| `includeValuesInResponse` | boolean | No | Whether to include the updated values in the response |
|
||||
@@ -120,7 +117,7 @@ Append data to the end of a specific sheet in a Google Sheets spreadsheet
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to append to |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to append to |
|
||||
| `range` | string | No | The A1 notation range to append after \(e.g. "Sheet1", "Sheet1!A:D"\) |
|
||||
| `values` | array | Yes | The data to append as a 2D array \(e.g. \[\["Alice", 30\], \["Bob", 25\]\]\) or array of objects. |
|
||||
| `valueInputOption` | string | No | The format of the data to append |
|
||||
| `insertDataOption` | string | No | How to insert the data \(OVERWRITE or INSERT_ROWS\) |
|
||||
@@ -139,4 +136,180 @@ Append data to the end of a specific sheet in a Google Sheets spreadsheet
|
||||
| ↳ `spreadsheetId` | string | Google Sheets spreadsheet ID |
|
||||
| ↳ `spreadsheetUrl` | string | Spreadsheet URL |
|
||||
|
||||
### `google_sheets_clear`
|
||||
|
||||
Clear values from a specific range in a Google Sheets spreadsheet
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to clear |
|
||||
| `cellRange` | string | No | The cell range to clear \(e.g. "A1:D10"\). Clears entire sheet if not specified. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `clearedRange` | string | The range that was cleared |
|
||||
| `sheetName` | string | Name of the sheet that was cleared |
|
||||
| `metadata` | json | Spreadsheet metadata including ID and URL |
|
||||
| ↳ `spreadsheetId` | string | Google Sheets spreadsheet ID |
|
||||
| ↳ `spreadsheetUrl` | string | Spreadsheet URL |
|
||||
|
||||
### `google_sheets_get_spreadsheet`
|
||||
|
||||
Get metadata about a Google Sheets spreadsheet including title and sheet list
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `includeGridData` | boolean | No | Whether to include grid data \(cell values\). Defaults to false. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `spreadsheetId` | string | The spreadsheet ID |
|
||||
| `title` | string | The title of the spreadsheet |
|
||||
| `locale` | string | The locale of the spreadsheet |
|
||||
| `timeZone` | string | The time zone of the spreadsheet |
|
||||
| `spreadsheetUrl` | string | URL to the spreadsheet |
|
||||
| `sheets` | array | List of sheets in the spreadsheet |
|
||||
| ↳ `sheetId` | number | The sheet ID |
|
||||
| ↳ `title` | string | The sheet title/name |
|
||||
| ↳ `index` | number | The sheet index \(position\) |
|
||||
| ↳ `rowCount` | number | Number of rows in the sheet |
|
||||
| ↳ `columnCount` | number | Number of columns in the sheet |
|
||||
| ↳ `hidden` | boolean | Whether the sheet is hidden |
|
||||
|
||||
### `google_sheets_create_spreadsheet`
|
||||
|
||||
Create a new Google Sheets spreadsheet
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `title` | string | Yes | The title of the new spreadsheet |
|
||||
| `sheetTitles` | json | No | Array of sheet names to create \(e.g., \["Sheet1", "Data", "Summary"\]\). Defaults to a single "Sheet1". |
|
||||
| `locale` | string | No | The locale of the spreadsheet \(e.g., "en_US"\) |
|
||||
| `timeZone` | string | No | The time zone of the spreadsheet \(e.g., "America/New_York"\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `spreadsheetId` | string | The ID of the created spreadsheet |
|
||||
| `title` | string | The title of the created spreadsheet |
|
||||
| `spreadsheetUrl` | string | URL to the created spreadsheet |
|
||||
| `sheets` | array | List of sheets created in the spreadsheet |
|
||||
| ↳ `sheetId` | number | The sheet ID |
|
||||
| ↳ `title` | string | The sheet title/name |
|
||||
| ↳ `index` | number | The sheet index \(position\) |
|
||||
|
||||
### `google_sheets_batch_get`
|
||||
|
||||
Read multiple ranges from a Google Sheets spreadsheet in a single request
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `ranges` | json | Yes | Array of ranges to read \(e.g., \["Sheet1!A1:D10", "Sheet2!A1:B5"\]\). Each range should include sheet name. |
|
||||
| `majorDimension` | string | No | The major dimension of values: "ROWS" \(default\) or "COLUMNS" |
|
||||
| `valueRenderOption` | string | No | How values should be rendered: "FORMATTED_VALUE" \(default\), "UNFORMATTED_VALUE", or "FORMULA" |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `spreadsheetId` | string | The spreadsheet ID |
|
||||
| `valueRanges` | array | Array of value ranges read from the spreadsheet |
|
||||
| ↳ `range` | string | The range that was read |
|
||||
| ↳ `majorDimension` | string | Major dimension \(ROWS or COLUMNS\) |
|
||||
| ↳ `values` | array | The cell values as a 2D array |
|
||||
| `metadata` | json | Spreadsheet metadata including ID and URL |
|
||||
| ↳ `spreadsheetId` | string | Google Sheets spreadsheet ID |
|
||||
| ↳ `spreadsheetUrl` | string | Spreadsheet URL |
|
||||
|
||||
### `google_sheets_batch_update`
|
||||
|
||||
Update multiple ranges in a Google Sheets spreadsheet in a single request
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `data` | json | Yes | Array of value ranges to update. Each item should have "range" \(e.g., "Sheet1!A1:D10"\) and "values" \(2D array\). |
|
||||
| `valueInputOption` | string | No | How input data should be interpreted: "RAW" or "USER_ENTERED" \(default\). USER_ENTERED parses formulas. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `spreadsheetId` | string | The spreadsheet ID |
|
||||
| `totalUpdatedRows` | number | Total number of rows updated |
|
||||
| `totalUpdatedColumns` | number | Total number of columns updated |
|
||||
| `totalUpdatedCells` | number | Total number of cells updated |
|
||||
| `totalUpdatedSheets` | number | Total number of sheets updated |
|
||||
| `responses` | array | Array of update responses for each range |
|
||||
| ↳ `spreadsheetId` | string | The spreadsheet ID |
|
||||
| ↳ `updatedRange` | string | The range that was updated |
|
||||
| ↳ `updatedRows` | number | Number of rows updated in this range |
|
||||
| ↳ `updatedColumns` | number | Number of columns updated in this range |
|
||||
| ↳ `updatedCells` | number | Number of cells updated in this range |
|
||||
| `metadata` | json | Spreadsheet metadata including ID and URL |
|
||||
| ↳ `spreadsheetId` | string | Google Sheets spreadsheet ID |
|
||||
| ↳ `spreadsheetUrl` | string | Spreadsheet URL |
|
||||
|
||||
### `google_sheets_batch_clear`
|
||||
|
||||
Clear multiple ranges in a Google Sheets spreadsheet in a single request
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet |
|
||||
| `ranges` | json | Yes | Array of ranges to clear \(e.g., \["Sheet1!A1:D10", "Sheet2!A1:B5"\]\). Each range should include sheet name. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `spreadsheetId` | string | The spreadsheet ID |
|
||||
| `clearedRanges` | array | Array of ranges that were cleared |
|
||||
| `metadata` | json | Spreadsheet metadata including ID and URL |
|
||||
| ↳ `spreadsheetId` | string | Google Sheets spreadsheet ID |
|
||||
| ↳ `spreadsheetUrl` | string | Spreadsheet URL |
|
||||
|
||||
### `google_sheets_copy_sheet`
|
||||
|
||||
Copy a sheet from one spreadsheet to another
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `sourceSpreadsheetId` | string | Yes | The ID of the source spreadsheet |
|
||||
| `sheetId` | number | Yes | The ID of the sheet to copy \(numeric ID, not the sheet name\). Use Get Spreadsheet to find sheet IDs. |
|
||||
| `destinationSpreadsheetId` | string | Yes | The ID of the destination spreadsheet where the sheet will be copied |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `sheetId` | number | The ID of the newly created sheet in the destination |
|
||||
| `title` | string | The title of the copied sheet |
|
||||
| `index` | number | The index \(position\) of the copied sheet |
|
||||
| `sheetType` | string | The type of the sheet \(GRID, CHART, etc.\) |
|
||||
| `destinationSpreadsheetId` | string | The ID of the destination spreadsheet |
|
||||
| `destinationSpreadsheetUrl` | string | URL to the destination spreadsheet |
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ In Sim, the Google Slides integration enables your agents to interact directly w
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Integrate Google Slides into the workflow. Can read, write, create presentations, replace text, add slides, add images, and get thumbnails.
|
||||
Integrate Google Slides into the workflow. Can read, write, create presentations, replace text, add slides, add images, get thumbnails, get page details, delete objects, duplicate objects, reorder slides, create tables, create shapes, and insert text.
|
||||
|
||||
|
||||
|
||||
@@ -177,4 +177,157 @@ Generate a thumbnail image of a specific slide in a Google Slides presentation
|
||||
| `height` | number | Height of the thumbnail in pixels |
|
||||
| `metadata` | json | Operation metadata including presentation ID and page object ID |
|
||||
|
||||
### `google_slides_get_page`
|
||||
|
||||
Get detailed information about a specific slide/page in a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `pageObjectId` | string | Yes | The object ID of the slide/page to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `objectId` | string | The object ID of the page |
|
||||
| `pageType` | string | The type of page \(SLIDE, MASTER, LAYOUT, NOTES, NOTES_MASTER\) |
|
||||
| `pageElements` | json | Array of page elements \(shapes, images, tables, etc.\) on this page |
|
||||
| `slideProperties` | json | Properties specific to slides \(layout, master, notes\) |
|
||||
| `metadata` | json | Operation metadata including presentation ID and URL |
|
||||
|
||||
### `google_slides_delete_object`
|
||||
|
||||
Delete a page element (shape, image, table, etc.) or an entire slide from a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `objectId` | string | Yes | The object ID of the element or slide to delete |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `deleted` | boolean | Whether the object was successfully deleted |
|
||||
| `objectId` | string | The object ID that was deleted |
|
||||
| `metadata` | json | Operation metadata including presentation ID and URL |
|
||||
|
||||
### `google_slides_duplicate_object`
|
||||
|
||||
Duplicate an object (slide, shape, image, table, etc.) in a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `objectId` | string | Yes | The object ID of the element or slide to duplicate |
|
||||
| `objectIds` | string | No | Optional JSON object mapping source object IDs \(within the slide being duplicated\) to new object IDs for the duplicates. Format: \{"sourceId1":"newId1","sourceId2":"newId2"\} |
|
||||
| `Format` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `duplicatedObjectId` | string | The object ID of the newly created duplicate |
|
||||
| `metadata` | json | Operation metadata including presentation ID and source object ID |
|
||||
|
||||
### `google_slides_update_slides_position`
|
||||
|
||||
Move one or more slides to a new position in a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `slideObjectIds` | string | Yes | Comma-separated list of slide object IDs to move. The slides will maintain their relative order. |
|
||||
| `insertionIndex` | number | Yes | The zero-based index where the slides should be moved. All slides with indices greater than or equal to this will be shifted right. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `moved` | boolean | Whether the slides were successfully moved |
|
||||
| `slideObjectIds` | array | The slide object IDs that were moved |
|
||||
| `insertionIndex` | number | The index where the slides were moved to |
|
||||
| `metadata` | json | Operation metadata including presentation ID and URL |
|
||||
|
||||
### `google_slides_create_table`
|
||||
|
||||
Create a new table on a slide in a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `pageObjectId` | string | Yes | The object ID of the slide/page to add the table to |
|
||||
| `rows` | number | Yes | Number of rows in the table \(minimum 1\) |
|
||||
| `columns` | number | Yes | Number of columns in the table \(minimum 1\) |
|
||||
| `width` | number | No | Width of the table in points \(default: 400\) |
|
||||
| `height` | number | No | Height of the table in points \(default: 200\) |
|
||||
| `positionX` | number | No | X position from the left edge in points \(default: 100\) |
|
||||
| `positionY` | number | No | Y position from the top edge in points \(default: 100\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `tableId` | string | The object ID of the newly created table |
|
||||
| `rows` | number | Number of rows in the table |
|
||||
| `columns` | number | Number of columns in the table |
|
||||
| `metadata` | json | Operation metadata including presentation ID and page object ID |
|
||||
|
||||
### `google_slides_create_shape`
|
||||
|
||||
Create a shape (rectangle, ellipse, text box, arrow, etc.) on a slide in a Google Slides presentation
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `pageObjectId` | string | Yes | The object ID of the slide/page to add the shape to |
|
||||
| `shapeType` | string | Yes | The type of shape to create. Common types: TEXT_BOX, RECTANGLE, ROUND_RECTANGLE, ELLIPSE, TRIANGLE, DIAMOND, STAR_5, ARROW_EAST, HEART, CLOUD |
|
||||
| `width` | number | No | Width of the shape in points \(default: 200\) |
|
||||
| `height` | number | No | Height of the shape in points \(default: 100\) |
|
||||
| `positionX` | number | No | X position from the left edge in points \(default: 100\) |
|
||||
| `positionY` | number | No | Y position from the top edge in points \(default: 100\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `shapeId` | string | The object ID of the newly created shape |
|
||||
| `shapeType` | string | The type of shape that was created |
|
||||
| `metadata` | json | Operation metadata including presentation ID and page object ID |
|
||||
|
||||
### `google_slides_insert_text`
|
||||
|
||||
Insert text into a shape or table cell in a Google Slides presentation. Use this to add text to text boxes, shapes, or table cells.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `presentationId` | string | Yes | The ID of the presentation |
|
||||
| `objectId` | string | Yes | The object ID of the shape or table cell to insert text into. For table cells, use the cell object ID. |
|
||||
| `text` | string | Yes | The text to insert |
|
||||
| `insertionIndex` | number | No | The zero-based index at which to insert the text. If not specified, text is inserted at the beginning \(index 0\). |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `inserted` | boolean | Whether the text was successfully inserted |
|
||||
| `objectId` | string | The object ID where text was inserted |
|
||||
| `text` | string | The text that was inserted |
|
||||
| `metadata` | json | Operation metadata including presentation ID and URL |
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ Search for similar content in a knowledge base using vector similarity
|
||||
| `properties` | string | No | No description |
|
||||
| `tagName` | string | No | No description |
|
||||
| `tagValue` | string | No | No description |
|
||||
| `tagFilters` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -108,19 +109,8 @@ Create a new document in a knowledge base
|
||||
| `knowledgeBaseId` | string | Yes | ID of the knowledge base containing the document |
|
||||
| `name` | string | Yes | Name of the document |
|
||||
| `content` | string | Yes | Content of the document |
|
||||
| `tag1` | string | No | Tag 1 value for the document |
|
||||
| `tag2` | string | No | Tag 2 value for the document |
|
||||
| `tag3` | string | No | Tag 3 value for the document |
|
||||
| `tag4` | string | No | Tag 4 value for the document |
|
||||
| `tag5` | string | No | Tag 5 value for the document |
|
||||
| `tag6` | string | No | Tag 6 value for the document |
|
||||
| `tag7` | string | No | Tag 7 value for the document |
|
||||
| `documentTagsData` | array | No | Structured tag data with names, types, and values |
|
||||
| `items` | object | No | No description |
|
||||
| `properties` | string | No | No description |
|
||||
| `tagName` | string | No | No description |
|
||||
| `tagValue` | string | No | No description |
|
||||
| `tagType` | string | No | No description |
|
||||
| `documentTags` | object | No | Document tags |
|
||||
| `documentTags` | string | No | No description |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -45,8 +45,7 @@ Read data from a specific sheet in a Microsoft Excel spreadsheet
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to read from |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to read from |
|
||||
| `cellRange` | string | No | The cell range to read \(e.g., "A1:D10"\). If not specified, reads the entire used range. |
|
||||
| `range` | string | No | The range of cells to read from. Accepts "SheetName!A1:B2" for explicit ranges or just "SheetName" to read the used range of that sheet. If omitted, reads the used range of the first sheet. |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -68,9 +67,8 @@ Write data to a specific sheet in a Microsoft Excel spreadsheet
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `spreadsheetId` | string | Yes | The ID of the spreadsheet to write to |
|
||||
| `sheetName` | string | Yes | The name of the sheet/tab to write to |
|
||||
| `cellRange` | string | No | The cell range to write to \(e.g., "A1:D10", "A1"\). Defaults to "A1" if not specified. |
|
||||
| `values` | array | Yes | The data to write as a 2D array \(e.g. \[\["Name", "Age"\], \["Alice", 30\], \["Bob", 25\]\]\) or array of objects. |
|
||||
| `range` | string | No | The range of cells to write to |
|
||||
| `values` | array | Yes | The data to write to the spreadsheet |
|
||||
| `valueInputOption` | string | No | The format of the data to write |
|
||||
| `includeValuesInResponse` | boolean | No | Whether to include the written values in the response |
|
||||
|
||||
|
||||
@@ -84,9 +84,10 @@ Send messages to Slack channels or direct messages. Supports Slack mrkdwn format
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `authMethod` | string | No | Authentication method: oauth or bot_token |
|
||||
| `destinationType` | string | No | Destination type: channel or dm |
|
||||
| `botToken` | string | No | Bot token for Custom Bot |
|
||||
| `channel` | string | No | Target Slack channel \(e.g., #general\) |
|
||||
| `userId` | string | No | Target Slack user ID for direct messages \(e.g., U1234567890\) |
|
||||
| `dmUserId` | string | No | Target Slack user for direct messages |
|
||||
| `text` | string | Yes | Message text to send \(supports Slack mrkdwn formatting\) |
|
||||
| `thread_ts` | string | No | Thread timestamp to reply to \(creates thread reply\) |
|
||||
| `files` | file[] | No | Files to attach to the message |
|
||||
@@ -132,9 +133,10 @@ Read the latest messages from Slack channels. Retrieve conversation history with
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `authMethod` | string | No | Authentication method: oauth or bot_token |
|
||||
| `destinationType` | string | No | Destination type: channel or dm |
|
||||
| `botToken` | string | No | Bot token for Custom Bot |
|
||||
| `channel` | string | No | Slack channel to read messages from \(e.g., #general\) |
|
||||
| `userId` | string | No | User ID for DM conversation \(e.g., U1234567890\) |
|
||||
| `dmUserId` | string | No | Target Slack user for DM conversation |
|
||||
| `limit` | number | No | Number of messages to retrieve \(default: 10, max: 15\) |
|
||||
| `oldest` | string | No | Start of time range \(timestamp\) |
|
||||
| `latest` | string | No | End of time range \(timestamp\) |
|
||||
|
||||
@@ -84,6 +84,44 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
|
||||
{ label: 'Create project', id: 'github_create_project' },
|
||||
{ label: 'Update project', id: 'github_update_project' },
|
||||
{ label: 'Delete project', id: 'github_delete_project' },
|
||||
// Search Operations
|
||||
{ label: 'Search code', id: 'github_search_code' },
|
||||
{ label: 'Search commits', id: 'github_search_commits' },
|
||||
{ label: 'Search issues', id: 'github_search_issues' },
|
||||
{ label: 'Search repositories', id: 'github_search_repos' },
|
||||
{ label: 'Search users', id: 'github_search_users' },
|
||||
// Commit Operations
|
||||
{ label: 'List commits', id: 'github_list_commits' },
|
||||
{ label: 'Get commit', id: 'github_get_commit' },
|
||||
{ label: 'Compare commits', id: 'github_compare_commits' },
|
||||
// Gist Operations
|
||||
{ label: 'Create gist', id: 'github_create_gist' },
|
||||
{ label: 'Get gist', id: 'github_get_gist' },
|
||||
{ label: 'List gists', id: 'github_list_gists' },
|
||||
{ label: 'Update gist', id: 'github_update_gist' },
|
||||
{ label: 'Delete gist', id: 'github_delete_gist' },
|
||||
{ label: 'Fork gist', id: 'github_fork_gist' },
|
||||
{ label: 'Star gist', id: 'github_star_gist' },
|
||||
{ label: 'Unstar gist', id: 'github_unstar_gist' },
|
||||
// Fork Operations
|
||||
{ label: 'Fork repository', id: 'github_fork_repo' },
|
||||
{ label: 'List forks', id: 'github_list_forks' },
|
||||
// Milestone Operations
|
||||
{ label: 'Create milestone', id: 'github_create_milestone' },
|
||||
{ label: 'Get milestone', id: 'github_get_milestone' },
|
||||
{ label: 'List milestones', id: 'github_list_milestones' },
|
||||
{ label: 'Update milestone', id: 'github_update_milestone' },
|
||||
{ label: 'Delete milestone', id: 'github_delete_milestone' },
|
||||
// Reaction Operations
|
||||
{ label: 'Add issue reaction', id: 'github_create_issue_reaction' },
|
||||
{ label: 'Remove issue reaction', id: 'github_delete_issue_reaction' },
|
||||
{ label: 'Add comment reaction', id: 'github_create_comment_reaction' },
|
||||
{ label: 'Remove comment reaction', id: 'github_delete_comment_reaction' },
|
||||
// Star Operations
|
||||
{ label: 'Star repository', id: 'github_star_repo' },
|
||||
{ label: 'Unstar repository', id: 'github_unstar_repo' },
|
||||
{ label: 'Check if starred', id: 'github_check_star' },
|
||||
{ label: 'List stargazers', id: 'github_list_stargazers' },
|
||||
],
|
||||
value: () => 'github_pr',
|
||||
},
|
||||
@@ -998,6 +1036,440 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_delete_project' },
|
||||
},
|
||||
// Search operations parameters
|
||||
{
|
||||
id: 'q',
|
||||
title: 'Search Query',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., react language:typescript',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'github_search_code',
|
||||
'github_search_commits',
|
||||
'github_search_issues',
|
||||
'github_search_repos',
|
||||
'github_search_users',
|
||||
],
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a GitHub search query based on the user's description.
|
||||
GitHub search supports these qualifiers:
|
||||
- For repos: language:python, stars:>1000, forks:>100, topic:react, user:owner, org:name, created:>2023-01-01
|
||||
- For code: repo:owner/name, path:src, extension:ts, language:javascript
|
||||
- For issues/PRs: is:issue, is:pr, is:open, is:closed, label:bug, author:user, assignee:user
|
||||
- For commits: repo:owner/name, author:user, committer:user, author-date:>2023-01-01
|
||||
- For users: type:user, type:org, followers:>100, repos:>10, location:city
|
||||
|
||||
Examples:
|
||||
- "Python repos with more than 1000 stars" -> language:python stars:>1000
|
||||
- "Open bugs in facebook/react" -> repo:facebook/react is:issue is:open label:bug
|
||||
- "TypeScript files in src folder" -> language:typescript path:src
|
||||
|
||||
Return ONLY the search query - no explanations.`,
|
||||
placeholder: 'Describe what you want to search for...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'sort',
|
||||
title: 'Sort By',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Best match', id: '' },
|
||||
{ label: 'Stars', id: 'stars' },
|
||||
{ label: 'Forks', id: 'forks' },
|
||||
{ label: 'Updated', id: 'updated' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_search_repos' },
|
||||
},
|
||||
{
|
||||
id: 'order',
|
||||
title: 'Order',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Descending', id: 'desc' },
|
||||
{ label: 'Ascending', id: 'asc' },
|
||||
],
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'github_search_code',
|
||||
'github_search_commits',
|
||||
'github_search_issues',
|
||||
'github_search_repos',
|
||||
'github_search_users',
|
||||
],
|
||||
},
|
||||
},
|
||||
// Commit operations parameters
|
||||
{
|
||||
id: 'sha',
|
||||
title: 'SHA or Branch',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., main or abc123',
|
||||
condition: { field: 'operation', value: 'github_list_commits' },
|
||||
},
|
||||
{
|
||||
id: 'author',
|
||||
title: 'Author Filter',
|
||||
type: 'short-input',
|
||||
placeholder: 'GitHub username or email',
|
||||
condition: { field: 'operation', value: 'github_list_commits' },
|
||||
},
|
||||
{
|
||||
id: 'since',
|
||||
title: 'Since Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'ISO 8601: 2024-01-01T00:00:00Z',
|
||||
condition: { field: 'operation', value: ['github_list_commits', 'github_list_gists'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone).
|
||||
Examples:
|
||||
- "last week" -> Calculate 7 days ago at 00:00:00Z
|
||||
- "yesterday" -> Calculate yesterday's date at 00:00:00Z
|
||||
- "beginning of this month" -> First day of current month at 00:00:00Z
|
||||
- "30 days ago" -> Calculate 30 days before current time
|
||||
- "January 1st 2024" -> 2024-01-01T00:00:00Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the start date (e.g., "last week", "beginning of month")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'until',
|
||||
title: 'Until Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'ISO 8601: 2024-12-31T23:59:59Z',
|
||||
condition: { field: 'operation', value: 'github_list_commits' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone).
|
||||
Examples:
|
||||
- "now" -> Current timestamp
|
||||
- "end of today" -> Today's date at 23:59:59Z
|
||||
- "end of last week" -> Calculate end of last week
|
||||
- "yesterday" -> Yesterday's date at 23:59:59Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the end date (e.g., "now", "end of yesterday")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'ref',
|
||||
title: 'Commit Reference',
|
||||
type: 'short-input',
|
||||
placeholder: 'SHA, branch, or tag',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_get_commit' },
|
||||
},
|
||||
{
|
||||
id: 'base',
|
||||
title: 'Base Reference',
|
||||
type: 'short-input',
|
||||
placeholder: 'Base branch/tag/SHA',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_compare_commits' },
|
||||
},
|
||||
{
|
||||
id: 'head',
|
||||
title: 'Head Reference',
|
||||
type: 'short-input',
|
||||
placeholder: 'Head branch/tag/SHA',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_compare_commits' },
|
||||
},
|
||||
// Gist operations parameters
|
||||
{
|
||||
id: 'gist_id',
|
||||
title: 'Gist ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., aa5a315d61ae9438b18d',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'github_get_gist',
|
||||
'github_update_gist',
|
||||
'github_delete_gist',
|
||||
'github_fork_gist',
|
||||
'github_star_gist',
|
||||
'github_unstar_gist',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
title: 'Description',
|
||||
type: 'short-input',
|
||||
placeholder: 'Gist description',
|
||||
condition: { field: 'operation', value: ['github_create_gist', 'github_update_gist'] },
|
||||
},
|
||||
{
|
||||
id: 'files',
|
||||
title: 'Files (JSON)',
|
||||
type: 'long-input',
|
||||
placeholder: '{"file.txt": {"content": "Hello"}}',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_create_gist' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a JSON object for GitHub Gist files based on the user's description.
|
||||
The format is: {"filename.ext": {"content": "file contents"}}
|
||||
|
||||
Examples:
|
||||
- "A Python hello world file" -> {"hello.py": {"content": "print('Hello, World!')"}}
|
||||
- "A README with project title" -> {"README.md": {"content": "# My Project\\n\\nDescription here"}}
|
||||
- "JavaScript function to add numbers" -> {"add.js": {"content": "function add(a, b) {\\n return a + b;\\n}"}}
|
||||
- "Two files: index.html and style.css" -> {"index.html": {"content": "<!DOCTYPE html>..."}, "style.css": {"content": "body { margin: 0; }"}}
|
||||
|
||||
Return ONLY valid JSON - no explanations, no markdown formatting.`,
|
||||
placeholder: 'Describe the files you want to create...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'files',
|
||||
title: 'Files (JSON)',
|
||||
type: 'long-input',
|
||||
placeholder: '{"file.txt": {"content": "Updated"}}',
|
||||
condition: { field: 'operation', value: 'github_update_gist' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a JSON object for updating GitHub Gist files based on the user's description.
|
||||
The format is: {"filename.ext": {"content": "new contents"}}
|
||||
To delete a file, set its value to null: {"old-file.txt": null}
|
||||
To rename a file, set the new filename: {"old-name.txt": {"filename": "new-name.txt", "content": "..."}}
|
||||
|
||||
Examples:
|
||||
- "Update hello.py to print goodbye" -> {"hello.py": {"content": "print('Goodbye!')"}}
|
||||
- "Delete the old readme" -> {"README.md": null}
|
||||
- "Rename script.js to main.js" -> {"script.js": {"filename": "main.js"}}
|
||||
|
||||
Return ONLY valid JSON - no explanations, no markdown formatting.`,
|
||||
placeholder: 'Describe the file changes...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'gist_public',
|
||||
title: 'Public',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Secret', id: 'false' },
|
||||
{ label: 'Public', id: 'true' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_create_gist' },
|
||||
},
|
||||
{
|
||||
id: 'username',
|
||||
title: 'Username',
|
||||
type: 'short-input',
|
||||
placeholder: 'GitHub username (optional)',
|
||||
condition: { field: 'operation', value: 'github_list_gists' },
|
||||
},
|
||||
// Fork operations parameters
|
||||
{
|
||||
id: 'organization',
|
||||
title: 'Organization',
|
||||
type: 'short-input',
|
||||
placeholder: 'Fork to org (optional)',
|
||||
condition: { field: 'operation', value: 'github_fork_repo' },
|
||||
},
|
||||
{
|
||||
id: 'fork_name',
|
||||
title: 'Fork Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Custom name (optional)',
|
||||
condition: { field: 'operation', value: 'github_fork_repo' },
|
||||
},
|
||||
{
|
||||
id: 'default_branch_only',
|
||||
title: 'Default Branch Only',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'No', id: 'false' },
|
||||
{ label: 'Yes', id: 'true' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_fork_repo' },
|
||||
},
|
||||
{
|
||||
id: 'fork_sort',
|
||||
title: 'Sort By',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Newest', id: 'newest' },
|
||||
{ label: 'Oldest', id: 'oldest' },
|
||||
{ label: 'Stargazers', id: 'stargazers' },
|
||||
{ label: 'Watchers', id: 'watchers' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_list_forks' },
|
||||
},
|
||||
// Milestone operations parameters
|
||||
{
|
||||
id: 'milestone_title',
|
||||
title: 'Milestone Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., v1.0 Release',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'github_create_milestone' },
|
||||
},
|
||||
{
|
||||
id: 'milestone_title',
|
||||
title: 'New Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Updated title (optional)',
|
||||
condition: { field: 'operation', value: 'github_update_milestone' },
|
||||
},
|
||||
{
|
||||
id: 'milestone_description',
|
||||
title: 'Description',
|
||||
type: 'long-input',
|
||||
placeholder: 'Milestone description',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_create_milestone', 'github_update_milestone'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'due_on',
|
||||
title: 'Due Date',
|
||||
type: 'short-input',
|
||||
placeholder: 'ISO 8601: 2024-12-31T23:59:59Z',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_create_milestone', 'github_update_milestone'],
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp for a milestone due date based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone).
|
||||
Examples:
|
||||
- "end of this month" -> Last day of current month at 23:59:59Z
|
||||
- "next Friday" -> Calculate next Friday's date at 23:59:59Z
|
||||
- "in 2 weeks" -> Calculate 14 days from now at 23:59:59Z
|
||||
- "December 31st" -> 2024-12-31T23:59:59Z (current year)
|
||||
- "Q1 2025" -> 2025-03-31T23:59:59Z (end of Q1)
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the due date (e.g., "end of month", "next Friday")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'milestone_number',
|
||||
title: 'Milestone Number',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 1',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_get_milestone', 'github_update_milestone', 'github_delete_milestone'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'milestone_state',
|
||||
title: 'State Filter',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Open', id: 'open' },
|
||||
{ label: 'Closed', id: 'closed' },
|
||||
{ label: 'All', id: 'all' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_list_milestones' },
|
||||
},
|
||||
{
|
||||
id: 'milestone_sort',
|
||||
title: 'Sort By',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Due Date', id: 'due_on' },
|
||||
{ label: 'Completeness', id: 'completeness' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'github_list_milestones' },
|
||||
},
|
||||
// Reaction operations parameters
|
||||
{
|
||||
id: 'reaction_content',
|
||||
title: 'Reaction',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: '👍 +1', id: '+1' },
|
||||
{ label: '👎 -1', id: '-1' },
|
||||
{ label: '😄 Laugh', id: 'laugh' },
|
||||
{ label: '😕 Confused', id: 'confused' },
|
||||
{ label: '❤️ Heart', id: 'heart' },
|
||||
{ label: '🎉 Hooray', id: 'hooray' },
|
||||
{ label: '🚀 Rocket', id: 'rocket' },
|
||||
{ label: '👀 Eyes', id: 'eyes' },
|
||||
],
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_create_issue_reaction', 'github_create_comment_reaction'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'issue_number',
|
||||
title: 'Issue Number',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 123',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_create_issue_reaction', 'github_delete_issue_reaction'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'reaction_id',
|
||||
title: 'Reaction ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 12345678',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_delete_issue_reaction', 'github_delete_comment_reaction'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comment_id',
|
||||
title: 'Comment ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 987654321',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['github_create_comment_reaction', 'github_delete_comment_reaction'],
|
||||
},
|
||||
},
|
||||
// Star operations parameters - owner/repo already covered by existing subBlocks
|
||||
{
|
||||
id: 'per_page',
|
||||
title: 'Results Per Page',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g., 30 (default: 30, max: 100)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'github_search_code',
|
||||
'github_search_commits',
|
||||
'github_search_issues',
|
||||
'github_search_repos',
|
||||
'github_search_users',
|
||||
'github_list_commits',
|
||||
'github_list_gists',
|
||||
'github_list_forks',
|
||||
'github_list_milestones',
|
||||
'github_list_stargazers',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'GitHub Token',
|
||||
@@ -1118,6 +1590,44 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
|
||||
'github_create_project',
|
||||
'github_update_project',
|
||||
'github_delete_project',
|
||||
// Search tools
|
||||
'github_search_code',
|
||||
'github_search_commits',
|
||||
'github_search_issues',
|
||||
'github_search_repos',
|
||||
'github_search_users',
|
||||
// Commit tools
|
||||
'github_list_commits',
|
||||
'github_get_commit',
|
||||
'github_compare_commits',
|
||||
// Gist tools
|
||||
'github_create_gist',
|
||||
'github_get_gist',
|
||||
'github_list_gists',
|
||||
'github_update_gist',
|
||||
'github_delete_gist',
|
||||
'github_fork_gist',
|
||||
'github_star_gist',
|
||||
'github_unstar_gist',
|
||||
// Fork tools
|
||||
'github_fork_repo',
|
||||
'github_list_forks',
|
||||
// Milestone tools
|
||||
'github_create_milestone',
|
||||
'github_get_milestone',
|
||||
'github_list_milestones',
|
||||
'github_update_milestone',
|
||||
'github_delete_milestone',
|
||||
// Reaction tools
|
||||
'github_create_issue_reaction',
|
||||
'github_delete_issue_reaction',
|
||||
'github_create_comment_reaction',
|
||||
'github_delete_comment_reaction',
|
||||
// Star tools
|
||||
'github_star_repo',
|
||||
'github_unstar_repo',
|
||||
'github_check_star',
|
||||
'github_list_stargazers',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -1234,6 +1744,75 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
|
||||
return 'github_update_project'
|
||||
case 'github_delete_project':
|
||||
return 'github_delete_project'
|
||||
// Search operations
|
||||
case 'github_search_code':
|
||||
return 'github_search_code'
|
||||
case 'github_search_commits':
|
||||
return 'github_search_commits'
|
||||
case 'github_search_issues':
|
||||
return 'github_search_issues'
|
||||
case 'github_search_repos':
|
||||
return 'github_search_repos'
|
||||
case 'github_search_users':
|
||||
return 'github_search_users'
|
||||
// Commit operations
|
||||
case 'github_list_commits':
|
||||
return 'github_list_commits'
|
||||
case 'github_get_commit':
|
||||
return 'github_get_commit'
|
||||
case 'github_compare_commits':
|
||||
return 'github_compare_commits'
|
||||
// Gist operations
|
||||
case 'github_create_gist':
|
||||
return 'github_create_gist'
|
||||
case 'github_get_gist':
|
||||
return 'github_get_gist'
|
||||
case 'github_list_gists':
|
||||
return 'github_list_gists'
|
||||
case 'github_update_gist':
|
||||
return 'github_update_gist'
|
||||
case 'github_delete_gist':
|
||||
return 'github_delete_gist'
|
||||
case 'github_fork_gist':
|
||||
return 'github_fork_gist'
|
||||
case 'github_star_gist':
|
||||
return 'github_star_gist'
|
||||
case 'github_unstar_gist':
|
||||
return 'github_unstar_gist'
|
||||
// Fork operations
|
||||
case 'github_fork_repo':
|
||||
return 'github_fork_repo'
|
||||
case 'github_list_forks':
|
||||
return 'github_list_forks'
|
||||
// Milestone operations
|
||||
case 'github_create_milestone':
|
||||
return 'github_create_milestone'
|
||||
case 'github_get_milestone':
|
||||
return 'github_get_milestone'
|
||||
case 'github_list_milestones':
|
||||
return 'github_list_milestones'
|
||||
case 'github_update_milestone':
|
||||
return 'github_update_milestone'
|
||||
case 'github_delete_milestone':
|
||||
return 'github_delete_milestone'
|
||||
// Reaction operations
|
||||
case 'github_create_issue_reaction':
|
||||
return 'github_create_issue_reaction'
|
||||
case 'github_delete_issue_reaction':
|
||||
return 'github_delete_issue_reaction'
|
||||
case 'github_create_comment_reaction':
|
||||
return 'github_create_comment_reaction'
|
||||
case 'github_delete_comment_reaction':
|
||||
return 'github_delete_comment_reaction'
|
||||
// Star operations
|
||||
case 'github_star_repo':
|
||||
return 'github_star_repo'
|
||||
case 'github_unstar_repo':
|
||||
return 'github_unstar_repo'
|
||||
case 'github_check_star':
|
||||
return 'github_check_star'
|
||||
case 'github_list_stargazers':
|
||||
return 'github_list_stargazers'
|
||||
default:
|
||||
return 'github_repo_info'
|
||||
}
|
||||
@@ -1297,6 +1876,38 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
|
||||
project_number: { type: 'number', description: 'Project number' },
|
||||
project_id: { type: 'string', description: 'Project node ID' },
|
||||
project_public: { type: 'boolean', description: 'Project public status' },
|
||||
// Search parameters
|
||||
q: { type: 'string', description: 'Search query with qualifiers' },
|
||||
sort: { type: 'string', description: 'Sort field' },
|
||||
order: { type: 'string', description: 'Sort order (asc or desc)' },
|
||||
// Commit parameters
|
||||
author: { type: 'string', description: 'Author filter' },
|
||||
committer: { type: 'string', description: 'Committer filter' },
|
||||
since: { type: 'string', description: 'Date filter (since)' },
|
||||
until: { type: 'string', description: 'Date filter (until)' },
|
||||
// Gist parameters
|
||||
gist_id: { type: 'string', description: 'Gist ID' },
|
||||
description: { type: 'string', description: 'Description' },
|
||||
files: { type: 'string', description: 'Files JSON object' },
|
||||
gist_public: { type: 'boolean', description: 'Public gist status' },
|
||||
username: { type: 'string', description: 'GitHub username' },
|
||||
// Fork parameters
|
||||
organization: { type: 'string', description: 'Target organization for fork' },
|
||||
fork_name: { type: 'string', description: 'Custom name for fork' },
|
||||
default_branch_only: { type: 'boolean', description: 'Fork only default branch' },
|
||||
fork_sort: { type: 'string', description: 'Fork list sort field' },
|
||||
// Milestone parameters
|
||||
milestone_title: { type: 'string', description: 'Milestone title' },
|
||||
milestone_description: { type: 'string', description: 'Milestone description' },
|
||||
due_on: { type: 'string', description: 'Milestone due date' },
|
||||
milestone_number: { type: 'number', description: 'Milestone number' },
|
||||
milestone_state: { type: 'string', description: 'Milestone state filter' },
|
||||
milestone_sort: { type: 'string', description: 'Milestone sort field' },
|
||||
// Reaction parameters
|
||||
reaction_content: { type: 'string', description: 'Reaction type' },
|
||||
reaction_id: { type: 'number', description: 'Reaction ID' },
|
||||
// Pagination parameters
|
||||
page: { type: 'number', description: 'Page number for pagination' },
|
||||
},
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Response content' },
|
||||
|
||||
@@ -25,6 +25,11 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
|
||||
{ label: 'Create Event', id: 'create' },
|
||||
{ label: 'List Events', id: 'list' },
|
||||
{ label: 'Get Event', id: 'get' },
|
||||
{ label: 'Update Event', id: 'update' },
|
||||
{ label: 'Delete Event', id: 'delete' },
|
||||
{ label: 'Move Event', id: 'move' },
|
||||
{ label: 'Get Recurring Instances', id: 'instances' },
|
||||
{ label: 'List Calendars', id: 'list_calendars' },
|
||||
{ label: 'Quick Add (Natural Language)', id: 'quick_add' },
|
||||
{ label: 'Invite Attendees', id: 'invite' },
|
||||
],
|
||||
@@ -39,7 +44,7 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
|
||||
requiredScopes: ['https://www.googleapis.com/auth/calendar'],
|
||||
placeholder: 'Select Google Calendar account',
|
||||
},
|
||||
// Calendar selector (basic mode)
|
||||
// Calendar selector (basic mode) - not needed for list_calendars
|
||||
{
|
||||
id: 'calendarId',
|
||||
title: 'Calendar',
|
||||
@@ -50,8 +55,9 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
|
||||
placeholder: 'Select calendar',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
condition: { field: 'operation', value: 'list_calendars', not: true },
|
||||
},
|
||||
// Manual calendar ID input (advanced mode)
|
||||
// Manual calendar ID input (advanced mode) - not needed for list_calendars
|
||||
{
|
||||
id: 'manualCalendarId',
|
||||
title: 'Calendar ID',
|
||||
@@ -59,6 +65,7 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
|
||||
canonicalParamId: 'calendarId',
|
||||
placeholder: 'Enter calendar ID (e.g., primary or calendar@gmail.com)',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'list_calendars', not: true },
|
||||
},
|
||||
|
||||
// Create Event Fields
|
||||
@@ -204,10 +211,179 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
title: 'Event ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Event ID',
|
||||
condition: { field: 'operation', value: ['get', 'invite'] },
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get', 'update', 'delete', 'move', 'instances', 'invite'],
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
|
||||
// Update Event Fields
|
||||
{
|
||||
id: 'summary',
|
||||
title: 'New Event Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Updated meeting title',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a clear, descriptive calendar event title based on the user's request.
|
||||
The title should be concise but informative about the event's purpose.
|
||||
|
||||
Return ONLY the event title - no explanations, no extra text.`,
|
||||
placeholder: 'Describe the new event title...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
title: 'New Description',
|
||||
type: 'long-input',
|
||||
placeholder: 'Updated event description',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a helpful calendar event description based on the user's request.
|
||||
Include relevant details like:
|
||||
- Purpose of the event
|
||||
- Agenda items
|
||||
- Preparation notes
|
||||
- Links or resources
|
||||
|
||||
Return ONLY the description - no explanations, no extra text.`,
|
||||
placeholder: 'Describe the new event details...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'location',
|
||||
title: 'New Location',
|
||||
type: 'short-input',
|
||||
placeholder: 'Updated location',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
{
|
||||
id: 'startDateTime',
|
||||
title: 'New Start Date & Time',
|
||||
type: 'short-input',
|
||||
placeholder: '2025-06-03T10:00:00-08:00',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp with timezone offset based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SS+HH:MM or YYYY-MM-DDTHH:MM:SS-HH:MM
|
||||
Examples:
|
||||
- "tomorrow at 2pm" -> Calculate tomorrow's date at 14:00:00 with local timezone offset
|
||||
- "next Monday at 9am" -> Calculate next Monday at 09:00:00 with local timezone offset
|
||||
- "in 2 hours" -> Calculate current time + 2 hours with local timezone offset
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the new start time (e.g., "tomorrow at 2pm")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'endDateTime',
|
||||
title: 'New End Date & Time',
|
||||
type: 'short-input',
|
||||
placeholder: '2025-06-03T11:00:00-08:00',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp with timezone offset based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SS+HH:MM or YYYY-MM-DDTHH:MM:SS-HH:MM
|
||||
Examples:
|
||||
- "tomorrow at 3pm" -> Calculate tomorrow's date at 15:00:00 with local timezone offset
|
||||
- "1 hour after start" -> Calculate start time + 1 hour with local timezone offset
|
||||
- "next Monday at 5pm" -> Calculate next Monday at 17:00:00 with local timezone offset
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the new end time (e.g., "tomorrow at 3pm")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'attendees',
|
||||
title: 'New Attendees (comma-separated emails)',
|
||||
type: 'short-input',
|
||||
placeholder: 'john@example.com, jane@example.com',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
|
||||
// Move Event Fields
|
||||
{
|
||||
id: 'destinationCalendarId',
|
||||
title: 'Destination Calendar ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'destination@group.calendar.google.com',
|
||||
condition: { field: 'operation', value: 'move' },
|
||||
required: true,
|
||||
},
|
||||
|
||||
// Instances Fields
|
||||
{
|
||||
id: 'timeMin',
|
||||
title: 'Start Time Filter',
|
||||
type: 'short-input',
|
||||
placeholder: '2025-06-03T00:00:00Z',
|
||||
condition: { field: 'operation', value: 'instances' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in UTC based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone).
|
||||
Examples:
|
||||
- "today" -> Calculate today's date at 00:00:00Z
|
||||
- "yesterday" -> Calculate yesterday's date at 00:00:00Z
|
||||
- "last week" -> Calculate 7 days ago at 00:00:00Z
|
||||
- "beginning of this month" -> Calculate the first day of current month at 00:00:00Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the start of time range (e.g., "today", "last week")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'timeMax',
|
||||
title: 'End Time Filter',
|
||||
type: 'short-input',
|
||||
placeholder: '2025-06-04T00:00:00Z',
|
||||
condition: { field: 'operation', value: 'instances' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate an ISO 8601 timestamp in UTC based on the user's description.
|
||||
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SSZ (UTC timezone).
|
||||
Examples:
|
||||
- "tomorrow" -> Calculate tomorrow's date at 00:00:00Z
|
||||
- "end of today" -> Calculate today's date at 23:59:59Z
|
||||
- "next week" -> Calculate 7 days from now at 00:00:00Z
|
||||
- "end of this month" -> Calculate the last day of current month at 23:59:59Z
|
||||
|
||||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe the end of time range (e.g., "tomorrow", "end of this week")...',
|
||||
generationType: 'timestamp',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'maxResults',
|
||||
title: 'Max Results',
|
||||
type: 'short-input',
|
||||
placeholder: '250',
|
||||
condition: { field: 'operation', value: ['instances', 'list_calendars'] },
|
||||
},
|
||||
|
||||
// List Calendars Fields
|
||||
{
|
||||
id: 'minAccessRole',
|
||||
title: 'Minimum Access Role',
|
||||
type: 'dropdown',
|
||||
condition: { field: 'operation', value: 'list_calendars' },
|
||||
options: [
|
||||
{ label: 'Any Role', id: '' },
|
||||
{ label: 'Free/Busy Reader', id: 'freeBusyReader' },
|
||||
{ label: 'Reader', id: 'reader' },
|
||||
{ label: 'Writer', id: 'writer' },
|
||||
{ label: 'Owner', id: 'owner' },
|
||||
],
|
||||
},
|
||||
|
||||
// Invite Attendees Fields
|
||||
{
|
||||
id: 'attendees',
|
||||
@@ -262,14 +438,14 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
required: true,
|
||||
},
|
||||
|
||||
// Notification setting (for create, quick_add, invite)
|
||||
// Notification setting (for create, update, delete, move, quick_add, invite)
|
||||
{
|
||||
id: 'sendUpdates',
|
||||
title: 'Send Email Notifications',
|
||||
type: 'dropdown',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['create', 'quick_add', 'invite'],
|
||||
value: ['create', 'update', 'delete', 'move', 'quick_add', 'invite'],
|
||||
},
|
||||
options: [
|
||||
{ label: 'All attendees', id: 'all' },
|
||||
@@ -283,6 +459,11 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
'google_calendar_create',
|
||||
'google_calendar_list',
|
||||
'google_calendar_get',
|
||||
'google_calendar_update',
|
||||
'google_calendar_delete',
|
||||
'google_calendar_move',
|
||||
'google_calendar_instances',
|
||||
'google_calendar_list_calendars',
|
||||
'google_calendar_quick_add',
|
||||
'google_calendar_invite',
|
||||
],
|
||||
@@ -295,6 +476,16 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
return 'google_calendar_list'
|
||||
case 'get':
|
||||
return 'google_calendar_get'
|
||||
case 'update':
|
||||
return 'google_calendar_update'
|
||||
case 'delete':
|
||||
return 'google_calendar_delete'
|
||||
case 'move':
|
||||
return 'google_calendar_move'
|
||||
case 'instances':
|
||||
return 'google_calendar_instances'
|
||||
case 'list_calendars':
|
||||
return 'google_calendar_list_calendars'
|
||||
case 'quick_add':
|
||||
return 'google_calendar_quick_add'
|
||||
case 'invite':
|
||||
@@ -341,10 +532,23 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
}
|
||||
|
||||
// Set default sendUpdates to 'all' if not specified for operations that support it
|
||||
if (['create', 'quick_add', 'invite'].includes(operation) && !processedParams.sendUpdates) {
|
||||
if (
|
||||
['create', 'update', 'delete', 'move', 'quick_add', 'invite'].includes(operation) &&
|
||||
!processedParams.sendUpdates
|
||||
) {
|
||||
processedParams.sendUpdates = 'all'
|
||||
}
|
||||
|
||||
// Convert maxResults to number if provided
|
||||
if (processedParams.maxResults && typeof processedParams.maxResults === 'string') {
|
||||
processedParams.maxResults = Number.parseInt(processedParams.maxResults, 10)
|
||||
}
|
||||
|
||||
// Remove empty minAccessRole
|
||||
if (processedParams.minAccessRole === '') {
|
||||
processedParams.minAccessRole = undefined
|
||||
}
|
||||
|
||||
return {
|
||||
credential,
|
||||
...processedParams,
|
||||
@@ -358,7 +562,7 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
calendarId: { type: 'string', description: 'Calendar identifier' },
|
||||
manualCalendarId: { type: 'string', description: 'Manual calendar identifier' },
|
||||
|
||||
// Create operation inputs
|
||||
// Create/Update operation inputs
|
||||
summary: { type: 'string', description: 'Event title' },
|
||||
description: { type: 'string', description: 'Event description' },
|
||||
location: { type: 'string', description: 'Event location' },
|
||||
@@ -366,13 +570,20 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
endDateTime: { type: 'string', description: 'Event end time' },
|
||||
attendees: { type: 'string', description: 'Attendee email list' },
|
||||
|
||||
// List operation inputs
|
||||
// List/Instances operation inputs
|
||||
timeMin: { type: 'string', description: 'Start time filter' },
|
||||
timeMax: { type: 'string', description: 'End time filter' },
|
||||
maxResults: { type: 'string', description: 'Maximum number of results' },
|
||||
|
||||
// Get/Invite operation inputs
|
||||
// Get/Update/Delete/Move/Instances/Invite operation inputs
|
||||
eventId: { type: 'string', description: 'Event identifier' },
|
||||
|
||||
// Move operation inputs
|
||||
destinationCalendarId: { type: 'string', description: 'Destination calendar ID' },
|
||||
|
||||
// List Calendars operation inputs
|
||||
minAccessRole: { type: 'string', description: 'Minimum access role filter' },
|
||||
|
||||
// Quick add inputs
|
||||
text: { type: 'string', description: 'Natural language event' },
|
||||
|
||||
@@ -384,7 +595,7 @@ Return ONLY the natural language event text - no explanations.`,
|
||||
},
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Operation response content' },
|
||||
metadata: { type: 'json', description: 'Event metadata' },
|
||||
metadata: { type: 'json', description: 'Event or calendar metadata' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -399,6 +610,11 @@ export const GoogleCalendarV2Block: BlockConfig<GoogleCalendarResponse> = {
|
||||
'google_calendar_create_v2',
|
||||
'google_calendar_list_v2',
|
||||
'google_calendar_get_v2',
|
||||
'google_calendar_update_v2',
|
||||
'google_calendar_delete_v2',
|
||||
'google_calendar_move_v2',
|
||||
'google_calendar_instances_v2',
|
||||
'google_calendar_list_calendars_v2',
|
||||
'google_calendar_quick_add_v2',
|
||||
'google_calendar_invite_v2',
|
||||
],
|
||||
@@ -413,6 +629,7 @@ export const GoogleCalendarV2Block: BlockConfig<GoogleCalendarResponse> = {
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
// Event outputs (create, get, update, move, quick_add, invite)
|
||||
id: { type: 'string', description: 'Event ID' },
|
||||
htmlLink: { type: 'string', description: 'Event link' },
|
||||
status: { type: 'string', description: 'Event status' },
|
||||
@@ -424,9 +641,17 @@ export const GoogleCalendarV2Block: BlockConfig<GoogleCalendarResponse> = {
|
||||
attendees: { type: 'json', description: 'Event attendees' },
|
||||
creator: { type: 'json', description: 'Event creator' },
|
||||
organizer: { type: 'json', description: 'Event organizer' },
|
||||
// List events outputs
|
||||
events: { type: 'json', description: 'List of events (list operation)' },
|
||||
// Delete outputs
|
||||
eventId: { type: 'string', description: 'Deleted event ID' },
|
||||
deleted: { type: 'boolean', description: 'Whether deletion was successful' },
|
||||
// Instances outputs
|
||||
instances: { type: 'json', description: 'List of recurring event instances' },
|
||||
// List calendars outputs
|
||||
calendars: { type: 'json', description: 'List of calendars' },
|
||||
// Common outputs
|
||||
nextPageToken: { type: 'string', description: 'Next page token' },
|
||||
nextSyncToken: { type: 'string', description: 'Next sync token' },
|
||||
timeZone: { type: 'string', description: 'Calendar time zone' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ import type { GoogleDriveResponse } from '@/tools/google_drive/types'
|
||||
export const GoogleDriveBlock: BlockConfig<GoogleDriveResponse> = {
|
||||
type: 'google_drive',
|
||||
name: 'Google Drive',
|
||||
description: 'Create, upload, and list files',
|
||||
description: 'Manage files, folders, and permissions',
|
||||
authMode: AuthMode.OAuth,
|
||||
longDescription: 'Integrate Google Drive into the workflow. Can create, upload, and list files.',
|
||||
longDescription:
|
||||
'Integrate Google Drive into the workflow. Can create, upload, download, copy, move, delete, share files and manage permissions.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_drive',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
@@ -20,13 +21,23 @@ export const GoogleDriveBlock: BlockConfig<GoogleDriveResponse> = {
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'List Files', id: 'list' },
|
||||
{ label: 'Get File Info', id: 'get_file' },
|
||||
{ label: 'Create Folder', id: 'create_folder' },
|
||||
{ label: 'Create File', id: 'create_file' },
|
||||
{ label: 'Upload File', id: 'upload' },
|
||||
{ label: 'Download File', id: 'download' },
|
||||
{ label: 'List Files', id: 'list' },
|
||||
{ label: 'Copy File', id: 'copy' },
|
||||
{ label: 'Update File', id: 'update' },
|
||||
{ label: 'Move to Trash', id: 'trash' },
|
||||
{ label: 'Restore from Trash', id: 'untrash' },
|
||||
{ label: 'Delete Permanently', id: 'delete' },
|
||||
{ label: 'Share File', id: 'share' },
|
||||
{ label: 'Remove Sharing', id: 'unshare' },
|
||||
{ label: 'List Permissions', id: 'list_permissions' },
|
||||
{ label: 'Get Drive Info', id: 'get_about' },
|
||||
],
|
||||
value: () => 'create_folder',
|
||||
value: () => 'list',
|
||||
},
|
||||
// Google Drive Credentials
|
||||
{
|
||||
@@ -326,26 +337,453 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
placeholder: 'Optional: Override the filename',
|
||||
condition: { field: 'operation', value: 'download' },
|
||||
},
|
||||
// Get File Info Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to get info for',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'get_file' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'get_file' },
|
||||
required: true,
|
||||
},
|
||||
// Copy File Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File to Copy',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to copy',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'copy' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to copy',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'copy' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'newName',
|
||||
title: 'New File Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Name for the copy (optional)',
|
||||
condition: { field: 'operation', value: 'copy' },
|
||||
},
|
||||
{
|
||||
id: 'folderSelector',
|
||||
title: 'Destination Folder',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'destinationFolderId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
mimeType: 'application/vnd.google-apps.folder',
|
||||
placeholder: 'Select destination folder (optional)',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'copy' },
|
||||
},
|
||||
{
|
||||
id: 'manualDestinationFolderId',
|
||||
title: 'Destination Folder ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'destinationFolderId',
|
||||
placeholder: 'Enter destination folder ID (optional)',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'copy' },
|
||||
},
|
||||
// Update File Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File to Update',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to update',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to update',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'name',
|
||||
title: 'New Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'New name for the file (optional)',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
title: 'Description',
|
||||
type: 'long-input',
|
||||
placeholder: 'New description for the file (optional)',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a clear, informative file description based on the user's input.
|
||||
The description should help users understand the file's purpose and contents.
|
||||
Keep it concise but comprehensive - typically 1-3 sentences.
|
||||
|
||||
Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
placeholder: 'Describe what this file is about...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'starred',
|
||||
title: 'Starred',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'No Change', id: '' },
|
||||
{ label: 'Star', id: 'true' },
|
||||
{ label: 'Unstar', id: 'false' },
|
||||
],
|
||||
placeholder: 'Star or unstar the file',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
{
|
||||
id: 'addParents',
|
||||
title: 'Add to Folders',
|
||||
type: 'short-input',
|
||||
placeholder: 'Comma-separated folder IDs to add file to',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
{
|
||||
id: 'removeParents',
|
||||
title: 'Remove from Folders',
|
||||
type: 'short-input',
|
||||
placeholder: 'Comma-separated folder IDs to remove file from',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
// Trash File Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File to Trash',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to move to trash',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'trash' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to trash',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'trash' },
|
||||
required: true,
|
||||
},
|
||||
// Untrash File Fields
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to restore from trash',
|
||||
condition: { field: 'operation', value: 'untrash' },
|
||||
required: true,
|
||||
},
|
||||
// Delete File Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File to Delete',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to permanently delete',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'delete' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to permanently delete',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'delete' },
|
||||
required: true,
|
||||
},
|
||||
// Share File Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File to Share',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to share',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'share' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID to share',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'share' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'shareType',
|
||||
title: 'Share With',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User (email)', id: 'user' },
|
||||
{ label: 'Group (email)', id: 'group' },
|
||||
{ label: 'Domain', id: 'domain' },
|
||||
{ label: 'Anyone with link', id: 'anyone' },
|
||||
],
|
||||
placeholder: 'Who to share with',
|
||||
condition: { field: 'operation', value: 'share' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'role',
|
||||
title: 'Permission Level',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Viewer (read only)', id: 'reader' },
|
||||
{ label: 'Commenter (view & comment)', id: 'commenter' },
|
||||
{ label: 'Editor (can edit)', id: 'writer' },
|
||||
{ label: 'Transfer Ownership', id: 'owner' },
|
||||
],
|
||||
placeholder: 'Permission level',
|
||||
condition: { field: 'operation', value: 'share' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'email',
|
||||
title: 'Email Address',
|
||||
type: 'short-input',
|
||||
placeholder: 'Email of user or group to share with',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'share',
|
||||
and: { field: 'shareType', value: ['user', 'group'] },
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'domain',
|
||||
title: 'Domain',
|
||||
type: 'short-input',
|
||||
placeholder: 'Domain to share with (e.g., example.com)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'share',
|
||||
and: { field: 'shareType', value: 'domain' },
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'sendNotification',
|
||||
title: 'Send Notification',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Yes (default)', id: 'true' },
|
||||
{ label: 'No', id: 'false' },
|
||||
],
|
||||
placeholder: 'Send email notification',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'share',
|
||||
and: { field: 'shareType', value: ['user', 'group'] },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'emailMessage',
|
||||
title: 'Custom Message',
|
||||
type: 'long-input',
|
||||
placeholder: 'Custom message for the notification email (optional)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'share',
|
||||
and: { field: 'shareType', value: ['user', 'group'] },
|
||||
},
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a professional, friendly sharing notification message based on the user's input.
|
||||
The message should clearly explain why the file is being shared and any relevant context.
|
||||
Keep it concise and appropriate for a business email - typically 2-4 sentences.
|
||||
|
||||
Return ONLY the message text - no subject line, no greetings/signatures, no extra formatting.`,
|
||||
placeholder: 'Describe why you are sharing this file...',
|
||||
},
|
||||
},
|
||||
// Unshare (Remove Permission) Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to remove sharing from',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'unshare' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'unshare' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'permissionId',
|
||||
title: 'Permission ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Permission ID to remove (use List Permissions to find)',
|
||||
condition: { field: 'operation', value: 'unshare' },
|
||||
required: true,
|
||||
},
|
||||
// List Permissions Fields
|
||||
{
|
||||
id: 'fileSelector',
|
||||
title: 'Select File',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'fileId',
|
||||
serviceId: 'google-drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select a file to list permissions for',
|
||||
mode: 'basic',
|
||||
dependsOn: ['credential'],
|
||||
condition: { field: 'operation', value: 'list_permissions' },
|
||||
},
|
||||
{
|
||||
id: 'manualFileId',
|
||||
title: 'File ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'fileId',
|
||||
placeholder: 'Enter file ID',
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'list_permissions' },
|
||||
required: true,
|
||||
},
|
||||
// Get Drive Info has no additional fields (just needs credential)
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'google_drive_upload',
|
||||
'google_drive_create_folder',
|
||||
'google_drive_download',
|
||||
'google_drive_list',
|
||||
'google_drive_get_file',
|
||||
'google_drive_create_folder',
|
||||
'google_drive_upload',
|
||||
'google_drive_download',
|
||||
'google_drive_copy',
|
||||
'google_drive_update',
|
||||
'google_drive_trash',
|
||||
'google_drive_untrash',
|
||||
'google_drive_delete',
|
||||
'google_drive_share',
|
||||
'google_drive_unshare',
|
||||
'google_drive_list_permissions',
|
||||
'google_drive_get_about',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'list':
|
||||
return 'google_drive_list'
|
||||
case 'get_file':
|
||||
return 'google_drive_get_file'
|
||||
case 'create_folder':
|
||||
return 'google_drive_create_folder'
|
||||
case 'create_file':
|
||||
case 'upload':
|
||||
return 'google_drive_upload'
|
||||
case 'create_folder':
|
||||
return 'google_drive_create_folder'
|
||||
case 'download':
|
||||
return 'google_drive_download'
|
||||
case 'list':
|
||||
return 'google_drive_list'
|
||||
case 'copy':
|
||||
return 'google_drive_copy'
|
||||
case 'update':
|
||||
return 'google_drive_update'
|
||||
case 'trash':
|
||||
return 'google_drive_trash'
|
||||
case 'untrash':
|
||||
return 'google_drive_untrash'
|
||||
case 'delete':
|
||||
return 'google_drive_delete'
|
||||
case 'share':
|
||||
return 'google_drive_share'
|
||||
case 'unshare':
|
||||
return 'google_drive_unshare'
|
||||
case 'list_permissions':
|
||||
return 'google_drive_list_permissions'
|
||||
case 'get_about':
|
||||
return 'google_drive_get_about'
|
||||
default:
|
||||
throw new Error(`Invalid Google Drive operation: ${params.operation}`)
|
||||
}
|
||||
@@ -355,9 +793,13 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
credential,
|
||||
folderSelector,
|
||||
manualFolderId,
|
||||
manualDestinationFolderId,
|
||||
fileSelector,
|
||||
manualFileId,
|
||||
mimeType,
|
||||
shareType,
|
||||
starred,
|
||||
sendNotification,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
@@ -367,12 +809,30 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
// Use fileSelector if provided, otherwise use manualFileId
|
||||
const effectiveFileId = (fileSelector || manualFileId || '').trim()
|
||||
|
||||
// Use folderSelector for destination or manualDestinationFolderId for copy operation
|
||||
const effectiveDestinationFolderId =
|
||||
params.operation === 'copy'
|
||||
? (folderSelector || manualDestinationFolderId || '').trim()
|
||||
: undefined
|
||||
|
||||
// Convert starred dropdown to boolean
|
||||
const starredValue = starred === 'true' ? true : starred === 'false' ? false : undefined
|
||||
|
||||
// Convert sendNotification dropdown to boolean
|
||||
const sendNotificationValue =
|
||||
sendNotification === 'true' ? true : sendNotification === 'false' ? false : undefined
|
||||
|
||||
return {
|
||||
credential,
|
||||
folderId: effectiveFolderId || undefined,
|
||||
fileId: effectiveFileId || undefined,
|
||||
destinationFolderId: effectiveDestinationFolderId || undefined,
|
||||
pageSize: rest.pageSize ? Number.parseInt(rest.pageSize as string, 10) : undefined,
|
||||
mimeType: mimeType,
|
||||
type: shareType, // Map shareType to type for share tool
|
||||
starred: starredValue,
|
||||
sendNotification: sendNotificationValue,
|
||||
transferOwnership: rest.role === 'owner' ? true : undefined,
|
||||
...rest,
|
||||
}
|
||||
},
|
||||
@@ -381,22 +841,47 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Google Drive access token' },
|
||||
// Upload and Create Folder operation inputs
|
||||
// File selection inputs
|
||||
fileSelector: { type: 'string', description: 'Selected file' },
|
||||
manualFileId: { type: 'string', description: 'Manual file identifier' },
|
||||
// Folder selection inputs
|
||||
folderSelector: { type: 'string', description: 'Selected folder' },
|
||||
manualFolderId: { type: 'string', description: 'Manual folder identifier' },
|
||||
manualDestinationFolderId: { type: 'string', description: 'Destination folder for copy' },
|
||||
// Upload and Create inputs
|
||||
fileName: { type: 'string', description: 'File or folder name' },
|
||||
file: { type: 'json', description: 'File to upload (UserFile object)' },
|
||||
content: { type: 'string', description: 'Text content to upload' },
|
||||
mimeType: { type: 'string', description: 'File MIME type or export format' },
|
||||
// Download operation inputs
|
||||
fileSelector: { type: 'string', description: 'Selected file to download' },
|
||||
manualFileId: { type: 'string', description: 'Manual file identifier' },
|
||||
// List operation inputs
|
||||
folderSelector: { type: 'string', description: 'Selected folder' },
|
||||
manualFolderId: { type: 'string', description: 'Manual folder identifier' },
|
||||
query: { type: 'string', description: 'Search query' },
|
||||
pageSize: { type: 'number', description: 'Results per page' },
|
||||
// Copy operation inputs
|
||||
newName: { type: 'string', description: 'New name for copied file' },
|
||||
// Update operation inputs
|
||||
name: { type: 'string', description: 'New name for file' },
|
||||
description: { type: 'string', description: 'New description for file' },
|
||||
starred: { type: 'string', description: 'Star or unstar the file' },
|
||||
addParents: { type: 'string', description: 'Folder IDs to add file to' },
|
||||
removeParents: { type: 'string', description: 'Folder IDs to remove file from' },
|
||||
// Share operation inputs
|
||||
shareType: { type: 'string', description: 'Type of sharing (user, group, domain, anyone)' },
|
||||
role: { type: 'string', description: 'Permission role' },
|
||||
email: { type: 'string', description: 'Email address to share with' },
|
||||
domain: { type: 'string', description: 'Domain to share with' },
|
||||
sendNotification: { type: 'string', description: 'Send notification email' },
|
||||
emailMessage: { type: 'string', description: 'Custom notification message' },
|
||||
// Unshare operation inputs
|
||||
permissionId: { type: 'string', description: 'Permission ID to remove' },
|
||||
},
|
||||
outputs: {
|
||||
file: { type: 'json', description: 'File data' },
|
||||
files: { type: 'json', description: 'Files list' },
|
||||
file: { type: 'json', description: 'File metadata' },
|
||||
files: { type: 'json', description: 'List of files' },
|
||||
permission: { type: 'json', description: 'Permission details' },
|
||||
permissions: { type: 'json', description: 'List of permissions' },
|
||||
user: { type: 'json', description: 'User information' },
|
||||
storageQuota: { type: 'json', description: 'Storage quota information' },
|
||||
deleted: { type: 'boolean', description: 'Whether file was deleted' },
|
||||
removed: { type: 'boolean', description: 'Whether permission was removed' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { GoogleFormsIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { getTrigger } from '@/triggers'
|
||||
|
||||
export const GoogleFormsBlock: BlockConfig = {
|
||||
type: 'google_forms',
|
||||
name: 'Google Forms',
|
||||
description: 'Read responses from a Google Form',
|
||||
longDescription:
|
||||
'Integrate Google Forms into your workflow. Provide a Form ID to list responses, or specify a Response ID to fetch a single response. Requires OAuth.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_forms',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GoogleFormsIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Google Account',
|
||||
type: 'oauth-input',
|
||||
required: true,
|
||||
serviceId: 'google-forms',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'https://www.googleapis.com/auth/forms.responses.readonly',
|
||||
],
|
||||
placeholder: 'Select Google account',
|
||||
},
|
||||
{
|
||||
id: 'formId',
|
||||
title: 'Form ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter the Google Form ID',
|
||||
dependsOn: ['credential'],
|
||||
},
|
||||
{
|
||||
id: 'responseId',
|
||||
title: 'Response ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter a specific response ID',
|
||||
},
|
||||
{
|
||||
id: 'pageSize',
|
||||
title: 'Page Size',
|
||||
type: 'short-input',
|
||||
placeholder: 'Max responses to retrieve (default 5000)',
|
||||
},
|
||||
...getTrigger('google_forms_webhook').subBlocks,
|
||||
],
|
||||
tools: {
|
||||
access: ['google_forms_get_responses'],
|
||||
config: {
|
||||
tool: () => 'google_forms_get_responses',
|
||||
params: (params) => {
|
||||
const { credential, formId, responseId, pageSize, ...rest } = params
|
||||
|
||||
const effectiveFormId = String(formId || '').trim()
|
||||
if (!effectiveFormId) {
|
||||
throw new Error('Form ID is required.')
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
formId: effectiveFormId,
|
||||
responseId: responseId ? String(responseId).trim() : undefined,
|
||||
pageSize: pageSize ? Number(pageSize) : undefined,
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
credential: { type: 'string', description: 'Google OAuth credential' },
|
||||
formId: { type: 'string', description: 'Google Form ID' },
|
||||
responseId: { type: 'string', description: 'Specific response ID' },
|
||||
pageSize: { type: 'string', description: 'Max responses to retrieve (default 5000)' },
|
||||
},
|
||||
outputs: {
|
||||
data: { type: 'json', description: 'Response or list of responses' },
|
||||
},
|
||||
triggers: {
|
||||
enabled: true,
|
||||
available: ['google_forms_webhook'],
|
||||
},
|
||||
}
|
||||
329
apps/sim/blocks/blocks/google_forms.ts
Normal file
329
apps/sim/blocks/blocks/google_forms.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
import { GoogleFormsIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { getTrigger } from '@/triggers'
|
||||
|
||||
export const GoogleFormsBlock: BlockConfig = {
|
||||
type: 'google_forms',
|
||||
name: 'Google Forms',
|
||||
description: 'Manage Google Forms and responses',
|
||||
longDescription:
|
||||
'Integrate Google Forms into your workflow. Read form structure, get responses, create forms, update content, and manage notification watches.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_forms',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GoogleFormsIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Get Responses', id: 'get_responses' },
|
||||
{ label: 'Get Form', id: 'get_form' },
|
||||
{ label: 'Create Form', id: 'create_form' },
|
||||
{ label: 'Batch Update', id: 'batch_update' },
|
||||
{ label: 'Set Publish Settings', id: 'set_publish_settings' },
|
||||
{ label: 'Create Watch', id: 'create_watch' },
|
||||
{ label: 'List Watches', id: 'list_watches' },
|
||||
{ label: 'Delete Watch', id: 'delete_watch' },
|
||||
{ label: 'Renew Watch', id: 'renew_watch' },
|
||||
],
|
||||
value: () => 'get_responses',
|
||||
},
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Google Account',
|
||||
type: 'oauth-input',
|
||||
required: true,
|
||||
serviceId: 'google-forms',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'https://www.googleapis.com/auth/forms.body',
|
||||
'https://www.googleapis.com/auth/forms.responses.readonly',
|
||||
],
|
||||
placeholder: 'Select Google account',
|
||||
},
|
||||
// Form ID - required for most operations except create_form
|
||||
{
|
||||
id: 'formId',
|
||||
title: 'Form ID',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter the Google Form ID',
|
||||
dependsOn: ['credential'],
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_form',
|
||||
not: true,
|
||||
},
|
||||
},
|
||||
// Get Responses specific fields
|
||||
{
|
||||
id: 'responseId',
|
||||
title: 'Response ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter a specific response ID (optional)',
|
||||
condition: { field: 'operation', value: 'get_responses' },
|
||||
},
|
||||
{
|
||||
id: 'pageSize',
|
||||
title: 'Page Size',
|
||||
type: 'short-input',
|
||||
placeholder: 'Max responses to retrieve (default 5000)',
|
||||
condition: { field: 'operation', value: 'get_responses' },
|
||||
},
|
||||
// Create Form specific fields
|
||||
{
|
||||
id: 'title',
|
||||
title: 'Form Title',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'Enter the form title',
|
||||
condition: { field: 'operation', value: 'create_form' },
|
||||
},
|
||||
{
|
||||
id: 'documentTitle',
|
||||
title: 'Document Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Title visible in Drive (optional)',
|
||||
condition: { field: 'operation', value: 'create_form' },
|
||||
},
|
||||
{
|
||||
id: 'unpublished',
|
||||
title: 'Create Unpublished',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'create_form' },
|
||||
},
|
||||
// Batch Update specific fields
|
||||
{
|
||||
id: 'requests',
|
||||
title: 'Update Requests',
|
||||
type: 'code',
|
||||
placeholder: 'JSON array of update requests',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a Google Forms batchUpdate requests array based on the user's description.
|
||||
|
||||
The requests array can contain these operation types:
|
||||
- updateFormInfo: Update form title/description. Structure: {updateFormInfo: {info: {title?, description?}, updateMask: "title,description"}}
|
||||
- updateSettings: Update form settings. Structure: {updateSettings: {settings: {quizSettings?: {isQuiz: boolean}}, updateMask: "quizSettings.isQuiz"}}
|
||||
- createItem: Add a question/section. Structure: {createItem: {item: {title, questionItem?: {question: {required?: boolean, choiceQuestion?: {type: "RADIO"|"CHECKBOX"|"DROP_DOWN", options: [{value: string}]}, textQuestion?: {paragraph?: boolean}, scaleQuestion?: {low: number, high: number}}}}, location: {index: number}}}
|
||||
- updateItem: Modify existing item. Structure: {updateItem: {item: {...}, location: {index: number}, updateMask: "..."}}
|
||||
- moveItem: Reorder item. Structure: {moveItem: {originalLocation: {index: number}, newLocation: {index: number}}}
|
||||
- deleteItem: Remove item. Structure: {deleteItem: {location: {index: number}}}
|
||||
|
||||
Return ONLY a valid JSON array of request objects. No explanations.
|
||||
|
||||
Example for "Add a required multiple choice question about favorite color":
|
||||
[{"createItem":{"item":{"title":"What is your favorite color?","questionItem":{"question":{"required":true,"choiceQuestion":{"type":"RADIO","options":[{"value":"Red"},{"value":"Blue"},{"value":"Green"}]}}}},"location":{"index":0}}}]`,
|
||||
placeholder: 'Describe what you want to add or change in the form...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'includeFormInResponse',
|
||||
title: 'Include Form in Response',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
// Set Publish Settings specific fields
|
||||
{
|
||||
id: 'isPublished',
|
||||
title: 'Published',
|
||||
type: 'switch',
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'set_publish_settings' },
|
||||
},
|
||||
{
|
||||
id: 'isAcceptingResponses',
|
||||
title: 'Accepting Responses',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'set_publish_settings' },
|
||||
},
|
||||
// Watch specific fields
|
||||
{
|
||||
id: 'eventType',
|
||||
title: 'Event Type',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Form Responses', id: 'RESPONSES' },
|
||||
{ label: 'Form Schema Changes', id: 'SCHEMA' },
|
||||
],
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'create_watch' },
|
||||
},
|
||||
{
|
||||
id: 'topicName',
|
||||
title: 'Pub/Sub Topic',
|
||||
type: 'short-input',
|
||||
required: true,
|
||||
placeholder: 'projects/{project}/topics/{topic}',
|
||||
condition: { field: 'operation', value: 'create_watch' },
|
||||
},
|
||||
{
|
||||
id: 'watchId',
|
||||
title: 'Watch ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Custom watch ID (optional)',
|
||||
condition: { field: 'operation', value: ['create_watch', 'delete_watch', 'renew_watch'] },
|
||||
required: { field: 'operation', value: ['delete_watch', 'renew_watch'] },
|
||||
},
|
||||
...getTrigger('google_forms_webhook').subBlocks,
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'google_forms_get_responses',
|
||||
'google_forms_get_form',
|
||||
'google_forms_create_form',
|
||||
'google_forms_batch_update',
|
||||
'google_forms_set_publish_settings',
|
||||
'google_forms_create_watch',
|
||||
'google_forms_list_watches',
|
||||
'google_forms_delete_watch',
|
||||
'google_forms_renew_watch',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'get_responses':
|
||||
return 'google_forms_get_responses'
|
||||
case 'get_form':
|
||||
return 'google_forms_get_form'
|
||||
case 'create_form':
|
||||
return 'google_forms_create_form'
|
||||
case 'batch_update':
|
||||
return 'google_forms_batch_update'
|
||||
case 'set_publish_settings':
|
||||
return 'google_forms_set_publish_settings'
|
||||
case 'create_watch':
|
||||
return 'google_forms_create_watch'
|
||||
case 'list_watches':
|
||||
return 'google_forms_list_watches'
|
||||
case 'delete_watch':
|
||||
return 'google_forms_delete_watch'
|
||||
case 'renew_watch':
|
||||
return 'google_forms_renew_watch'
|
||||
default:
|
||||
throw new Error(`Invalid Google Forms operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const {
|
||||
credential,
|
||||
operation,
|
||||
formId,
|
||||
responseId,
|
||||
pageSize,
|
||||
title,
|
||||
documentTitle,
|
||||
unpublished,
|
||||
requests,
|
||||
includeFormInResponse,
|
||||
isPublished,
|
||||
isAcceptingResponses,
|
||||
eventType,
|
||||
topicName,
|
||||
watchId,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const baseParams = { ...rest, credential }
|
||||
const effectiveFormId = formId ? String(formId).trim() : undefined
|
||||
|
||||
switch (operation) {
|
||||
case 'get_responses':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
return {
|
||||
...baseParams,
|
||||
formId: effectiveFormId,
|
||||
responseId: responseId ? String(responseId).trim() : undefined,
|
||||
pageSize: pageSize ? Number(pageSize) : undefined,
|
||||
}
|
||||
case 'get_form':
|
||||
case 'list_watches':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
return { ...baseParams, formId: effectiveFormId }
|
||||
case 'create_form':
|
||||
if (!title) throw new Error('Form title is required.')
|
||||
return {
|
||||
...baseParams,
|
||||
title: String(title).trim(),
|
||||
documentTitle: documentTitle ? String(documentTitle).trim() : undefined,
|
||||
unpublished: unpublished ?? false,
|
||||
}
|
||||
case 'batch_update':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
if (!requests) throw new Error('Update requests are required.')
|
||||
return {
|
||||
...baseParams,
|
||||
formId: effectiveFormId,
|
||||
requests: typeof requests === 'string' ? JSON.parse(requests) : requests,
|
||||
includeFormInResponse: includeFormInResponse ?? false,
|
||||
}
|
||||
case 'set_publish_settings':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
return {
|
||||
...baseParams,
|
||||
formId: effectiveFormId,
|
||||
isPublished: isPublished ?? false,
|
||||
isAcceptingResponses: isAcceptingResponses,
|
||||
}
|
||||
case 'create_watch':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
if (!eventType) throw new Error('Event type is required.')
|
||||
if (!topicName) throw new Error('Pub/Sub topic is required.')
|
||||
return {
|
||||
...baseParams,
|
||||
formId: effectiveFormId,
|
||||
eventType: String(eventType),
|
||||
topicName: String(topicName).trim(),
|
||||
watchId: watchId ? String(watchId).trim() : undefined,
|
||||
}
|
||||
case 'delete_watch':
|
||||
case 'renew_watch':
|
||||
if (!effectiveFormId) throw new Error('Form ID is required.')
|
||||
if (!watchId) throw new Error('Watch ID is required.')
|
||||
return {
|
||||
...baseParams,
|
||||
formId: effectiveFormId,
|
||||
watchId: String(watchId).trim(),
|
||||
}
|
||||
default:
|
||||
throw new Error(`Invalid Google Forms operation: ${operation}`)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Google OAuth credential' },
|
||||
formId: { type: 'string', description: 'Google Form ID' },
|
||||
responseId: { type: 'string', description: 'Specific response ID' },
|
||||
pageSize: { type: 'string', description: 'Max responses to retrieve' },
|
||||
title: { type: 'string', description: 'Form title for creation' },
|
||||
documentTitle: { type: 'string', description: 'Document title in Drive' },
|
||||
unpublished: { type: 'boolean', description: 'Create as unpublished' },
|
||||
requests: { type: 'json', description: 'Batch update requests' },
|
||||
includeFormInResponse: { type: 'boolean', description: 'Include form in response' },
|
||||
isPublished: { type: 'boolean', description: 'Form published state' },
|
||||
isAcceptingResponses: { type: 'boolean', description: 'Form accepting responses' },
|
||||
eventType: { type: 'string', description: 'Watch event type' },
|
||||
topicName: { type: 'string', description: 'Pub/Sub topic name' },
|
||||
watchId: { type: 'string', description: 'Watch ID' },
|
||||
},
|
||||
outputs: {
|
||||
response: { type: 'json', description: 'Operation response data' },
|
||||
formId: { type: 'string', description: 'Form ID' },
|
||||
title: { type: 'string', description: 'Form title' },
|
||||
responderUri: { type: 'string', description: 'Form responder URL' },
|
||||
items: { type: 'json', description: 'Form items' },
|
||||
responses: { type: 'json', description: 'Form responses' },
|
||||
watches: { type: 'json', description: 'Form watches' },
|
||||
},
|
||||
triggers: {
|
||||
enabled: true,
|
||||
available: ['google_forms_webhook'],
|
||||
},
|
||||
}
|
||||
@@ -30,6 +30,11 @@ export const GoogleGroupsBlock: BlockConfig = {
|
||||
{ label: 'Update Member Role', id: 'update_member' },
|
||||
{ label: 'Remove Member', id: 'remove_member' },
|
||||
{ label: 'Check Membership', id: 'has_member' },
|
||||
{ label: 'List Aliases', id: 'list_aliases' },
|
||||
{ label: 'Add Alias', id: 'add_alias' },
|
||||
{ label: 'Remove Alias', id: 'remove_alias' },
|
||||
{ label: 'Get Settings', id: 'get_settings' },
|
||||
{ label: 'Update Settings', id: 'update_settings' },
|
||||
],
|
||||
value: () => 'list_groups',
|
||||
},
|
||||
@@ -112,10 +117,37 @@ Return ONLY the query string - no explanations, no quotes, no extra text.`,
|
||||
'update_member',
|
||||
'remove_member',
|
||||
'has_member',
|
||||
'list_aliases',
|
||||
'add_alias',
|
||||
'remove_alias',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'groupEmail',
|
||||
title: 'Group Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'group@example.com',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_settings', 'update_settings'],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'alias',
|
||||
title: 'Alias Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'alias@example.com',
|
||||
required: true,
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['add_alias', 'remove_alias'],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'email',
|
||||
title: 'Group Email',
|
||||
@@ -233,6 +265,11 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
'google_groups_remove_member',
|
||||
'google_groups_update_member',
|
||||
'google_groups_has_member',
|
||||
'google_groups_list_aliases',
|
||||
'google_groups_add_alias',
|
||||
'google_groups_remove_alias',
|
||||
'google_groups_get_settings',
|
||||
'google_groups_update_settings',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -259,6 +296,16 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
return 'google_groups_remove_member'
|
||||
case 'has_member':
|
||||
return 'google_groups_has_member'
|
||||
case 'list_aliases':
|
||||
return 'google_groups_list_aliases'
|
||||
case 'add_alias':
|
||||
return 'google_groups_add_alias'
|
||||
case 'remove_alias':
|
||||
return 'google_groups_remove_alias'
|
||||
case 'get_settings':
|
||||
return 'google_groups_get_settings'
|
||||
case 'update_settings':
|
||||
return 'google_groups_update_settings'
|
||||
default:
|
||||
throw new Error(`Invalid Google Groups operation: ${params.operation}`)
|
||||
}
|
||||
@@ -330,6 +377,33 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
groupKey: rest.groupKey,
|
||||
memberKey: rest.memberKey,
|
||||
}
|
||||
case 'list_aliases':
|
||||
return {
|
||||
credential,
|
||||
groupKey: rest.groupKey,
|
||||
}
|
||||
case 'add_alias':
|
||||
return {
|
||||
credential,
|
||||
groupKey: rest.groupKey,
|
||||
alias: rest.alias,
|
||||
}
|
||||
case 'remove_alias':
|
||||
return {
|
||||
credential,
|
||||
groupKey: rest.groupKey,
|
||||
alias: rest.alias,
|
||||
}
|
||||
case 'get_settings':
|
||||
return {
|
||||
credential,
|
||||
groupEmail: rest.groupEmail,
|
||||
}
|
||||
case 'update_settings':
|
||||
return {
|
||||
credential,
|
||||
groupEmail: rest.groupEmail,
|
||||
}
|
||||
default:
|
||||
return { credential, ...rest }
|
||||
}
|
||||
@@ -353,6 +427,8 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
memberEmail: { type: 'string', description: 'Email of member to add' },
|
||||
role: { type: 'string', description: 'Member role (MEMBER, MANAGER, OWNER)' },
|
||||
roles: { type: 'string', description: 'Filter by roles for list members' },
|
||||
alias: { type: 'string', description: 'Alias email address' },
|
||||
groupEmail: { type: 'string', description: 'Group email address for settings operations' },
|
||||
},
|
||||
outputs: {
|
||||
groups: { type: 'json', description: 'Array of group objects (for list_groups)' },
|
||||
@@ -362,5 +438,8 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
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' },
|
||||
aliases: { type: 'json', description: 'Array of alias objects (for list_aliases)' },
|
||||
settings: { type: 'json', description: 'Group settings object (for get/update_settings)' },
|
||||
deleted: { type: 'boolean', description: 'Deletion result (for remove_alias)' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GoogleSheetsIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { GoogleSheetsResponse } from '@/tools/google_sheets/types'
|
||||
import type { GoogleSheetsResponse, GoogleSheetsV2Response } from '@/tools/google_sheets/types'
|
||||
|
||||
// Legacy block - hidden from toolbar
|
||||
export const GoogleSheetsBlock: BlockConfig<GoogleSheetsResponse> = {
|
||||
@@ -284,3 +284,725 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
tableRange: { type: 'string', description: 'Table range' },
|
||||
},
|
||||
}
|
||||
|
||||
export const GoogleSheetsV2Block: BlockConfig<GoogleSheetsV2Response> = {
|
||||
type: 'google_sheets_v2',
|
||||
name: 'Google Sheets',
|
||||
description: 'Read, write, and update data with sheet selection',
|
||||
authMode: AuthMode.OAuth,
|
||||
hideFromToolbar: false,
|
||||
longDescription:
|
||||
'Integrate Google Sheets into the workflow with explicit sheet selection. Can read, write, append, update, clear data, create spreadsheets, get spreadsheet info, and copy sheets.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_sheets',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GoogleSheetsIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Read Data', id: 'read' },
|
||||
{ label: 'Write Data', id: 'write' },
|
||||
{ label: 'Update Data', id: 'update' },
|
||||
{ label: 'Append Data', id: 'append' },
|
||||
{ label: 'Clear Data', id: 'clear' },
|
||||
{ label: 'Get Spreadsheet Info', id: 'get_info' },
|
||||
{ label: 'Create Spreadsheet', id: 'create' },
|
||||
{ label: 'Batch Read', id: 'batch_get' },
|
||||
{ label: 'Batch Update', id: 'batch_update' },
|
||||
{ label: 'Batch Clear', id: 'batch_clear' },
|
||||
{ label: 'Copy Sheet', id: 'copy_sheet' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
// Google Sheets Credentials
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Google Account',
|
||||
type: 'oauth-input',
|
||||
required: true,
|
||||
serviceId: 'google-sheets',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select Google account',
|
||||
},
|
||||
// Spreadsheet Selector (basic mode) - not for create operation
|
||||
{
|
||||
id: 'spreadsheetId',
|
||||
title: 'Select Spreadsheet',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'google-sheets',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
mimeType: 'application/vnd.google-apps.spreadsheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
condition: { field: 'operation', value: 'create', not: true },
|
||||
},
|
||||
// Manual Spreadsheet ID (advanced mode) - not for create operation
|
||||
{
|
||||
id: 'manualSpreadsheetId',
|
||||
title: 'Spreadsheet ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
placeholder: 'ID of the spreadsheet (from URL)',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: 'create', not: true },
|
||||
},
|
||||
// Sheet Name Selector (basic mode) - for operations that need sheet name
|
||||
{
|
||||
id: 'sheetName',
|
||||
title: 'Sheet (Tab)',
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'google-sheets',
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
mode: 'basic',
|
||||
condition: { field: 'operation', value: ['read', 'write', 'update', 'append', 'clear'] },
|
||||
},
|
||||
// Manual Sheet Name (advanced mode) - for operations that need sheet name
|
||||
{
|
||||
id: 'manualSheetName',
|
||||
title: 'Sheet Name',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'sheetName',
|
||||
placeholder: 'Name of the sheet/tab (e.g., Sheet1)',
|
||||
required: true,
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
condition: { field: 'operation', value: ['read', 'write', 'update', 'append', 'clear'] },
|
||||
},
|
||||
// Cell Range (optional for read/write/update/clear)
|
||||
{
|
||||
id: 'cellRange',
|
||||
title: 'Cell Range',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cell range (e.g., A1:D10). Defaults to A1 for write.',
|
||||
condition: { field: 'operation', value: ['read', 'write', 'update', 'clear'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a valid cell range based on the user's description.
|
||||
|
||||
### VALID FORMATS
|
||||
- Single cell: A1
|
||||
- Range: A1:D10
|
||||
- Entire column: A:A
|
||||
- Entire row: 1:1
|
||||
- Multiple columns: A:D
|
||||
- Multiple rows: 1:10
|
||||
|
||||
### RANGE RULES
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB, etc.
|
||||
- Row numbers start at 1 (not 0)
|
||||
|
||||
### EXAMPLES
|
||||
- "first 100 rows" -> A1:Z100
|
||||
- "cells A1 through C50" -> A1:C50
|
||||
- "column A" -> A:A
|
||||
- "just the headers row" -> 1:1
|
||||
- "first cell" -> A1
|
||||
|
||||
Return ONLY the range string - no sheet name, no explanations, no quotes.`,
|
||||
placeholder: 'Describe the range (e.g., "first 50 rows" or "column A")...',
|
||||
},
|
||||
},
|
||||
// Write-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects (e.g., [{"name":"John", "age":30}])',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "sales data with product and revenue columns" -> [["Product", "Revenue"], ["Widget A", 1500], ["Widget B", 2300]]
|
||||
- "list of employees with name and email" -> [{"name": "John Doe", "email": "john@example.com"}, {"name": "Jane Smith", "email": "jane@example.com"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to write...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: ['write', 'batch_update'] },
|
||||
},
|
||||
// Update-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "update with new prices" -> [["Product", "Price"], ["Widget A", 29.99], ["Widget B", 49.99]]
|
||||
- "quarterly targets" -> [{"Q1": 10000, "Q2": 12000, "Q3": 15000, "Q4": 18000}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to update...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
// Append-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects',
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Value1", "Value2"], ["Value3", "Value4"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "add new sales record" -> [["2024-01-15", "Widget Pro", 5, 249.99]]
|
||||
- "append customer info" -> [{"name": "Acme Corp", "contact": "John Smith", "status": "Active"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to append...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'insertDataOption',
|
||||
title: 'Insert Data Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Insert Rows (Add new rows)', id: 'INSERT_ROWS' },
|
||||
{ label: 'Overwrite (Add to existing data)', id: 'OVERWRITE' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
},
|
||||
// Create Spreadsheet Fields
|
||||
{
|
||||
id: 'title',
|
||||
title: 'Spreadsheet Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Title for the new spreadsheet',
|
||||
condition: { field: 'operation', value: 'create' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'sheetTitles',
|
||||
title: 'Sheet Names',
|
||||
type: 'short-input',
|
||||
placeholder: 'Comma-separated sheet names (e.g., Sheet1, Data, Summary)',
|
||||
condition: { field: 'operation', value: 'create' },
|
||||
},
|
||||
// Batch Get Fields
|
||||
{
|
||||
id: 'ranges',
|
||||
title: 'Ranges',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'JSON array of ranges to read (e.g., ["Sheet1!A1:D10", "Sheet2!A1:B5"]). Include sheet name in each range.',
|
||||
condition: { field: 'operation', value: 'batch_get' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a JSON array of Google Sheets ranges based on the user's description.
|
||||
|
||||
### FORMAT
|
||||
Return a JSON array of range strings. Each range must include the sheet name.
|
||||
Format: ["SheetName!CellRange", "SheetName!CellRange", ...]
|
||||
|
||||
### RANGE RULES
|
||||
- Always include sheet name: Sheet1!A1:D10 (not just A1:D10)
|
||||
- Sheet names with spaces must be quoted: 'My Sheet'!A1:B10
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB
|
||||
- Row numbers start at 1
|
||||
- For entire column: Sheet1!A:A
|
||||
- For entire row: Sheet1!1:1
|
||||
|
||||
### EXAMPLES
|
||||
- "all data from Sales and the summary from Reports" -> ["Sales!A1:Z1000", "Reports!A1:D20"]
|
||||
- "first 100 rows from Sheet1 and Sheet2" -> ["Sheet1!A1:Z100", "Sheet2!A1:Z100"]
|
||||
- "headers from all three sheets" -> ["Sheet1!1:1", "Sheet2!1:1", "Sheet3!1:1"]
|
||||
- "column A from Products and Orders" -> ["Products!A:A", "Orders!A:A"]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder:
|
||||
'Describe the ranges you want to read (e.g., "all data from Sales and summary from Reports")...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
// Batch Update Fields
|
||||
{
|
||||
id: 'batchData',
|
||||
title: 'Data',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'JSON array of {range, values} objects (e.g., [{"range": "Sheet1!A1:B2", "values": [["A","B"],["C","D"]]}])',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a JSON array of data updates for Google Sheets based on the user's description.
|
||||
|
||||
### FORMAT
|
||||
Return a JSON array where each item has:
|
||||
- "range": The target range including sheet name (e.g., "Sheet1!A1:B2")
|
||||
- "values": A 2D array of values to write
|
||||
|
||||
Format: [{"range": "SheetName!CellRange", "values": [[row1], [row2], ...]}, ...]
|
||||
|
||||
### RANGE RULES
|
||||
- Always include sheet name: Sheet1!A1:D10
|
||||
- Sheet names with spaces must be quoted: 'My Sheet'!A1:B10
|
||||
- The range size should match the values array dimensions
|
||||
|
||||
### EXAMPLES
|
||||
- "set headers to Name, Email, Phone in Sheet1 and Status, Date in Sheet2" ->
|
||||
[{"range": "Sheet1!A1:C1", "values": [["Name", "Email", "Phone"]]}, {"range": "Sheet2!A1:B1", "values": [["Status", "Date"]]}]
|
||||
|
||||
- "add totals row in A10 of Sales with formula" ->
|
||||
[{"range": "Sales!A10:B10", "values": [["Total", "=SUM(B1:B9)"]]}]
|
||||
|
||||
- "update the first three rows of data in Products" ->
|
||||
[{"range": "Products!A2:C4", "values": [["Widget", 10, 29.99], ["Gadget", 5, 49.99], ["Tool", 20, 9.99]]}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder:
|
||||
'Describe the updates (e.g., "set headers in Sheet1 and add totals in Sheet2")...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
// Batch Clear Fields
|
||||
{
|
||||
id: 'ranges',
|
||||
title: 'Ranges to Clear',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'JSON array of ranges to clear (e.g., ["Sheet1!A1:D10", "Sheet2!A1:B5"]). Include sheet name in each range.',
|
||||
condition: { field: 'operation', value: 'batch_clear' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a JSON array of Google Sheets ranges to clear based on the user's description.
|
||||
|
||||
### FORMAT
|
||||
Return a JSON array of range strings. Each range must include the sheet name.
|
||||
Format: ["SheetName!CellRange", "SheetName!CellRange", ...]
|
||||
|
||||
### RANGE RULES
|
||||
- Always include sheet name: Sheet1!A1:D10 (not just A1:D10)
|
||||
- Sheet names with spaces must be quoted: 'My Sheet'!A1:B10
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB
|
||||
- Row numbers start at 1
|
||||
- For entire column: Sheet1!A:A
|
||||
- For entire row: Sheet1!1:1
|
||||
- For entire sheet: Sheet1!A:ZZ (or use large range)
|
||||
|
||||
### EXAMPLES
|
||||
- "clear all data from Sales and Reports" -> ["Sales!A1:ZZ10000", "Reports!A1:ZZ10000"]
|
||||
- "clear rows 2-100 from Sheet1 and Sheet2, keep headers" -> ["Sheet1!A2:ZZ100", "Sheet2!A2:ZZ100"]
|
||||
- "clear column A from Products and Orders" -> ["Products!A:A", "Orders!A:A"]
|
||||
- "clear the summary section in Reports" -> ["Reports!A1:D20"]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder:
|
||||
'Describe the ranges to clear (e.g., "clear all data from Sales and Reports, keep headers")...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
// Copy Sheet Fields
|
||||
{
|
||||
id: 'sheetId',
|
||||
title: 'Sheet ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Numeric ID of the sheet to copy (use Get Spreadsheet Info to find IDs)',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'destinationSpreadsheetId',
|
||||
title: 'Destination Spreadsheet ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'ID of the spreadsheet to copy to',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'google_sheets_read_v2',
|
||||
'google_sheets_write_v2',
|
||||
'google_sheets_update_v2',
|
||||
'google_sheets_append_v2',
|
||||
'google_sheets_clear_v2',
|
||||
'google_sheets_get_spreadsheet_v2',
|
||||
'google_sheets_create_spreadsheet_v2',
|
||||
'google_sheets_batch_get_v2',
|
||||
'google_sheets_batch_update_v2',
|
||||
'google_sheets_batch_clear_v2',
|
||||
'google_sheets_copy_sheet_v2',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'read':
|
||||
return 'google_sheets_read_v2'
|
||||
case 'write':
|
||||
return 'google_sheets_write_v2'
|
||||
case 'update':
|
||||
return 'google_sheets_update_v2'
|
||||
case 'append':
|
||||
return 'google_sheets_append_v2'
|
||||
case 'clear':
|
||||
return 'google_sheets_clear_v2'
|
||||
case 'get_info':
|
||||
return 'google_sheets_get_spreadsheet_v2'
|
||||
case 'create':
|
||||
return 'google_sheets_create_spreadsheet_v2'
|
||||
case 'batch_get':
|
||||
return 'google_sheets_batch_get_v2'
|
||||
case 'batch_update':
|
||||
return 'google_sheets_batch_update_v2'
|
||||
case 'batch_clear':
|
||||
return 'google_sheets_batch_clear_v2'
|
||||
case 'copy_sheet':
|
||||
return 'google_sheets_copy_sheet_v2'
|
||||
default:
|
||||
throw new Error(`Invalid Google Sheets V2 operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const {
|
||||
credential,
|
||||
values,
|
||||
spreadsheetId,
|
||||
manualSpreadsheetId,
|
||||
sheetName,
|
||||
manualSheetName,
|
||||
cellRange,
|
||||
title,
|
||||
sheetTitles,
|
||||
ranges,
|
||||
batchData,
|
||||
sheetId,
|
||||
destinationSpreadsheetId,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const operation = params.operation as string
|
||||
|
||||
// Handle create operation
|
||||
if (operation === 'create') {
|
||||
const sheetTitlesArray = sheetTitles
|
||||
? (sheetTitles as string).split(',').map((s: string) => s.trim())
|
||||
: undefined
|
||||
return {
|
||||
title: (title as string)?.trim(),
|
||||
sheetTitles: sheetTitlesArray,
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
const effectiveSpreadsheetId = (
|
||||
(spreadsheetId || manualSpreadsheetId || '') as string
|
||||
).trim()
|
||||
|
||||
if (!effectiveSpreadsheetId) {
|
||||
throw new Error('Spreadsheet ID is required.')
|
||||
}
|
||||
|
||||
// Handle get_info operation
|
||||
if (operation === 'get_info') {
|
||||
return {
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle batch_get operation
|
||||
if (operation === 'batch_get') {
|
||||
const parsedRanges = ranges ? JSON.parse(ranges as string) : []
|
||||
return {
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
ranges: parsedRanges,
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle batch_update operation
|
||||
if (operation === 'batch_update') {
|
||||
const parsedData = batchData ? JSON.parse(batchData as string) : []
|
||||
return {
|
||||
...rest,
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
data: parsedData,
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle batch_clear operation
|
||||
if (operation === 'batch_clear') {
|
||||
const parsedRanges = ranges ? JSON.parse(ranges as string) : []
|
||||
return {
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
ranges: parsedRanges,
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle copy_sheet operation
|
||||
if (operation === 'copy_sheet') {
|
||||
return {
|
||||
sourceSpreadsheetId: effectiveSpreadsheetId,
|
||||
sheetId: Number.parseInt(sheetId as string, 10),
|
||||
destinationSpreadsheetId: (destinationSpreadsheetId as string)?.trim(),
|
||||
credential,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle read/write/update/append/clear operations (require sheet name)
|
||||
const effectiveSheetName = ((sheetName || manualSheetName || '') as string).trim()
|
||||
|
||||
if (!effectiveSheetName) {
|
||||
throw new Error('Sheet name is required. Please select or enter a sheet name.')
|
||||
}
|
||||
|
||||
const parsedValues = values ? JSON.parse(values as string) : undefined
|
||||
|
||||
return {
|
||||
...rest,
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
sheetName: effectiveSheetName,
|
||||
cellRange: cellRange ? (cellRange as string).trim() : undefined,
|
||||
values: parsedValues,
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Google Sheets access token' },
|
||||
spreadsheetId: { type: 'string', description: 'Spreadsheet identifier' },
|
||||
manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' },
|
||||
sheetName: { type: 'string', description: 'Name of the sheet/tab' },
|
||||
manualSheetName: { type: 'string', description: 'Manual sheet name entry' },
|
||||
cellRange: { type: 'string', description: 'Cell range (e.g., A1:D10)' },
|
||||
values: { type: 'string', description: 'Cell values data' },
|
||||
valueInputOption: { type: 'string', description: 'Value input option' },
|
||||
insertDataOption: { type: 'string', description: 'Data insertion option' },
|
||||
title: { type: 'string', description: 'Title for new spreadsheet' },
|
||||
sheetTitles: { type: 'string', description: 'Comma-separated sheet names for new spreadsheet' },
|
||||
ranges: { type: 'string', description: 'JSON array of ranges for batch operations' },
|
||||
batchData: { type: 'string', description: 'JSON array of data for batch update' },
|
||||
sheetId: { type: 'string', description: 'Numeric sheet ID for copy operation' },
|
||||
destinationSpreadsheetId: {
|
||||
type: 'string',
|
||||
description: 'Destination spreadsheet ID for copy',
|
||||
},
|
||||
},
|
||||
outputs: {
|
||||
// Read outputs
|
||||
sheetName: {
|
||||
type: 'string',
|
||||
description: 'Name of the sheet',
|
||||
condition: { field: 'operation', value: ['read', 'clear'] },
|
||||
},
|
||||
range: {
|
||||
type: 'string',
|
||||
description: 'Range that was read',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
values: {
|
||||
type: 'json',
|
||||
description: 'Cell values as 2D array',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
// Write/Update/Append outputs
|
||||
updatedRange: {
|
||||
type: 'string',
|
||||
description: 'Updated range',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedRows: {
|
||||
type: 'number',
|
||||
description: 'Updated rows count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedColumns: {
|
||||
type: 'number',
|
||||
description: 'Updated columns count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedCells: {
|
||||
type: 'number',
|
||||
description: 'Updated cells count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
tableRange: {
|
||||
type: 'string',
|
||||
description: 'Table range',
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
},
|
||||
// Clear outputs
|
||||
clearedRange: {
|
||||
type: 'string',
|
||||
description: 'Range that was cleared',
|
||||
condition: { field: 'operation', value: 'clear' },
|
||||
},
|
||||
// Get Info / Create / Batch outputs
|
||||
spreadsheetId: {
|
||||
type: 'string',
|
||||
description: 'Spreadsheet ID',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_info', 'create', 'batch_get', 'batch_update', 'batch_clear'],
|
||||
},
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Spreadsheet title (or copied sheet title for copy_sheet)',
|
||||
condition: { field: 'operation', value: ['get_info', 'create', 'copy_sheet'] },
|
||||
},
|
||||
sheets: {
|
||||
type: 'json',
|
||||
description: 'List of sheets in the spreadsheet',
|
||||
condition: { field: 'operation', value: ['get_info', 'create'] },
|
||||
},
|
||||
locale: {
|
||||
type: 'string',
|
||||
description: 'Spreadsheet locale',
|
||||
condition: { field: 'operation', value: 'get_info' },
|
||||
},
|
||||
timeZone: {
|
||||
type: 'string',
|
||||
description: 'Spreadsheet time zone',
|
||||
condition: { field: 'operation', value: 'get_info' },
|
||||
},
|
||||
spreadsheetUrl: {
|
||||
type: 'string',
|
||||
description: 'Spreadsheet URL',
|
||||
condition: { field: 'operation', value: ['get_info', 'create'] },
|
||||
},
|
||||
// Batch Get outputs
|
||||
valueRanges: {
|
||||
type: 'json',
|
||||
description: 'Array of value ranges read from the spreadsheet',
|
||||
condition: { field: 'operation', value: 'batch_get' },
|
||||
},
|
||||
// Batch Update outputs
|
||||
totalUpdatedRows: {
|
||||
type: 'number',
|
||||
description: 'Total rows updated',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
totalUpdatedColumns: {
|
||||
type: 'number',
|
||||
description: 'Total columns updated',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
totalUpdatedCells: {
|
||||
type: 'number',
|
||||
description: 'Total cells updated',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
totalUpdatedSheets: {
|
||||
type: 'number',
|
||||
description: 'Total sheets updated',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
responses: {
|
||||
type: 'json',
|
||||
description: 'Array of update responses for each range',
|
||||
condition: { field: 'operation', value: 'batch_update' },
|
||||
},
|
||||
// Batch Clear outputs
|
||||
clearedRanges: {
|
||||
type: 'json',
|
||||
description: 'Array of ranges that were cleared',
|
||||
condition: { field: 'operation', value: 'batch_clear' },
|
||||
},
|
||||
// Copy Sheet outputs
|
||||
sheetId: {
|
||||
type: 'number',
|
||||
description: 'ID of the copied sheet in the destination',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
},
|
||||
index: {
|
||||
type: 'number',
|
||||
description: 'Position/index of the copied sheet',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
},
|
||||
sheetType: {
|
||||
type: 'string',
|
||||
description: 'Type of the sheet (GRID, CHART, etc.)',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
},
|
||||
destinationSpreadsheetId: {
|
||||
type: 'string',
|
||||
description: 'ID of the destination spreadsheet',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
},
|
||||
destinationSpreadsheetUrl: {
|
||||
type: 'string',
|
||||
description: 'URL of the destination spreadsheet',
|
||||
condition: { field: 'operation', value: 'copy_sheet' },
|
||||
},
|
||||
// Common metadata
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Spreadsheet metadata including ID and URL',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'read',
|
||||
'write',
|
||||
'update',
|
||||
'append',
|
||||
'clear',
|
||||
'batch_get',
|
||||
'batch_update',
|
||||
'batch_clear',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,360 +0,0 @@
|
||||
import { GoogleSheetsIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { GoogleSheetsV2Response } from '@/tools/google_sheets/types'
|
||||
|
||||
export const GoogleSheetsV2Block: BlockConfig<GoogleSheetsV2Response> = {
|
||||
type: 'google_sheets_v2',
|
||||
name: 'Google Sheets',
|
||||
description: 'Read, write, and update data with sheet selection',
|
||||
authMode: AuthMode.OAuth,
|
||||
hideFromToolbar: false,
|
||||
longDescription:
|
||||
'Integrate Google Sheets into the workflow with explicit sheet selection. Can read, write, append, and update data in specific sheets.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_sheets',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GoogleSheetsIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Read Data', id: 'read' },
|
||||
{ label: 'Write Data', id: 'write' },
|
||||
{ label: 'Update Data', id: 'update' },
|
||||
{ label: 'Append Data', id: 'append' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
// Google Sheets Credentials
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Google Account',
|
||||
type: 'oauth-input',
|
||||
required: true,
|
||||
serviceId: 'google-sheets',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
placeholder: 'Select Google account',
|
||||
},
|
||||
// Spreadsheet Selector (basic mode)
|
||||
{
|
||||
id: 'spreadsheetId',
|
||||
title: 'Select Spreadsheet',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'google-sheets',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
],
|
||||
mimeType: 'application/vnd.google-apps.spreadsheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Spreadsheet ID (advanced mode)
|
||||
{
|
||||
id: 'manualSpreadsheetId',
|
||||
title: 'Spreadsheet ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
placeholder: 'ID of the spreadsheet (from URL)',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Sheet Name Selector (basic mode)
|
||||
{
|
||||
id: 'sheetName',
|
||||
title: 'Sheet (Tab)',
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'google-sheets',
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Sheet Name (advanced mode)
|
||||
{
|
||||
id: 'manualSheetName',
|
||||
title: 'Sheet Name',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'sheetName',
|
||||
placeholder: 'Name of the sheet/tab (e.g., Sheet1)',
|
||||
required: true,
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Cell Range (optional for read/write/update)
|
||||
{
|
||||
id: 'cellRange',
|
||||
title: 'Cell Range',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cell range (e.g., A1:D10). Defaults to A1 for write.',
|
||||
condition: { field: 'operation', value: ['read', 'write', 'update'] },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a valid cell range based on the user's description.
|
||||
|
||||
### VALID FORMATS
|
||||
- Single cell: A1
|
||||
- Range: A1:D10
|
||||
- Entire column: A:A
|
||||
- Entire row: 1:1
|
||||
- Multiple columns: A:D
|
||||
- Multiple rows: 1:10
|
||||
|
||||
### RANGE RULES
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB, etc.
|
||||
- Row numbers start at 1 (not 0)
|
||||
|
||||
### EXAMPLES
|
||||
- "first 100 rows" -> A1:Z100
|
||||
- "cells A1 through C50" -> A1:C50
|
||||
- "column A" -> A:A
|
||||
- "just the headers row" -> 1:1
|
||||
- "first cell" -> A1
|
||||
|
||||
Return ONLY the range string - no sheet name, no explanations, no quotes.`,
|
||||
placeholder: 'Describe the range (e.g., "first 50 rows" or "column A")...',
|
||||
},
|
||||
},
|
||||
// Write-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects (e.g., [{"name":"John", "age":30}])',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "sales data with product and revenue columns" -> [["Product", "Revenue"], ["Widget A", 1500], ["Widget B", 2300]]
|
||||
- "list of employees with name and email" -> [{"name": "John Doe", "email": "john@example.com"}, {"name": "Jane Smith", "email": "jane@example.com"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to write...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
// Update-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects',
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "update with new prices" -> [["Product", "Price"], ["Widget A", 29.99], ["Widget B", 49.99]]
|
||||
- "quarterly targets" -> [{"Q1": 10000, "Q2": 12000, "Q3": 15000, "Q4": 18000}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to update...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'update' },
|
||||
},
|
||||
// Append-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects',
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Google Sheets data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Value1", "Value2"], ["Value3", "Value4"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "add new sales record" -> [["2024-01-15", "Widget Pro", 5, 249.99]]
|
||||
- "append customer info" -> [{"name": "Acme Corp", "contact": "John Smith", "status": "Active"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to append...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
},
|
||||
{
|
||||
id: 'insertDataOption',
|
||||
title: 'Insert Data Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Insert Rows (Add new rows)', id: 'INSERT_ROWS' },
|
||||
{ label: 'Overwrite (Add to existing data)', id: 'OVERWRITE' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
'google_sheets_read_v2',
|
||||
'google_sheets_write_v2',
|
||||
'google_sheets_update_v2',
|
||||
'google_sheets_append_v2',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'read':
|
||||
return 'google_sheets_read_v2'
|
||||
case 'write':
|
||||
return 'google_sheets_write_v2'
|
||||
case 'update':
|
||||
return 'google_sheets_update_v2'
|
||||
case 'append':
|
||||
return 'google_sheets_append_v2'
|
||||
default:
|
||||
throw new Error(`Invalid Google Sheets V2 operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const {
|
||||
credential,
|
||||
values,
|
||||
spreadsheetId,
|
||||
manualSpreadsheetId,
|
||||
sheetName,
|
||||
manualSheetName,
|
||||
cellRange,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const parsedValues = values ? JSON.parse(values as string) : undefined
|
||||
|
||||
const effectiveSpreadsheetId = (spreadsheetId || manualSpreadsheetId || '').trim()
|
||||
const effectiveSheetName = ((sheetName || manualSheetName || '') as string).trim()
|
||||
|
||||
if (!effectiveSpreadsheetId) {
|
||||
throw new Error('Spreadsheet ID is required.')
|
||||
}
|
||||
|
||||
if (!effectiveSheetName) {
|
||||
throw new Error('Sheet name is required. Please select or enter a sheet name.')
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
sheetName: effectiveSheetName,
|
||||
cellRange: cellRange ? (cellRange as string).trim() : undefined,
|
||||
values: parsedValues,
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Google Sheets access token' },
|
||||
spreadsheetId: { type: 'string', description: 'Spreadsheet identifier' },
|
||||
manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' },
|
||||
sheetName: { type: 'string', description: 'Name of the sheet/tab' },
|
||||
manualSheetName: { type: 'string', description: 'Manual sheet name entry' },
|
||||
cellRange: { type: 'string', description: 'Cell range (e.g., A1:D10)' },
|
||||
values: { type: 'string', description: 'Cell values data' },
|
||||
valueInputOption: { type: 'string', description: 'Value input option' },
|
||||
insertDataOption: { type: 'string', description: 'Data insertion option' },
|
||||
},
|
||||
outputs: {
|
||||
sheetName: {
|
||||
type: 'string',
|
||||
description: 'Name of the sheet',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
range: {
|
||||
type: 'string',
|
||||
description: 'Range that was read',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
values: {
|
||||
type: 'json',
|
||||
description: 'Cell values as 2D array',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
updatedRange: {
|
||||
type: 'string',
|
||||
description: 'Updated range',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedRows: {
|
||||
type: 'number',
|
||||
description: 'Updated rows count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedColumns: {
|
||||
type: 'number',
|
||||
description: 'Updated columns count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
updatedCells: {
|
||||
type: 'number',
|
||||
description: 'Updated cells count',
|
||||
condition: { field: 'operation', value: ['write', 'update', 'append'] },
|
||||
},
|
||||
tableRange: {
|
||||
type: 'string',
|
||||
description: 'Table range',
|
||||
condition: { field: 'operation', value: 'append' },
|
||||
},
|
||||
metadata: { type: 'json', description: 'Spreadsheet metadata including ID and URL' },
|
||||
},
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export const GoogleSlidesBlock: BlockConfig<GoogleSlidesResponse> = {
|
||||
description: 'Read, write, and create presentations',
|
||||
authMode: AuthMode.OAuth,
|
||||
longDescription:
|
||||
'Integrate Google Slides into the workflow. Can read, write, create presentations, replace text, add slides, add images, and get thumbnails.',
|
||||
'Integrate Google Slides into the workflow. Can read, write, create presentations, replace text, add slides, add images, get thumbnails, get page details, delete objects, duplicate objects, reorder slides, create tables, create shapes, and insert text.',
|
||||
docsLink: 'https://docs.sim.ai/tools/google_slides',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
@@ -28,6 +28,13 @@ export const GoogleSlidesBlock: BlockConfig<GoogleSlidesResponse> = {
|
||||
{ label: 'Add Slide', id: 'add_slide' },
|
||||
{ label: 'Add Image', id: 'add_image' },
|
||||
{ label: 'Get Thumbnail', id: 'get_thumbnail' },
|
||||
{ label: 'Get Page', id: 'get_page' },
|
||||
{ label: 'Delete Object', id: 'delete_object' },
|
||||
{ label: 'Duplicate Object', id: 'duplicate_object' },
|
||||
{ label: 'Reorder Slides', id: 'reorder_slides' },
|
||||
{ label: 'Create Table', id: 'create_table' },
|
||||
{ label: 'Create Shape', id: 'create_shape' },
|
||||
{ label: 'Insert Text', id: 'insert_text' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
@@ -58,7 +65,21 @@ export const GoogleSlidesBlock: BlockConfig<GoogleSlidesResponse> = {
|
||||
mode: 'basic',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['read', 'write', 'replace_all_text', 'add_slide', 'add_image', 'get_thumbnail'],
|
||||
value: [
|
||||
'read',
|
||||
'write',
|
||||
'replace_all_text',
|
||||
'add_slide',
|
||||
'add_image',
|
||||
'get_thumbnail',
|
||||
'get_page',
|
||||
'delete_object',
|
||||
'duplicate_object',
|
||||
'reorder_slides',
|
||||
'create_table',
|
||||
'create_shape',
|
||||
'insert_text',
|
||||
],
|
||||
},
|
||||
},
|
||||
// Manual presentation ID input (advanced mode)
|
||||
@@ -72,7 +93,21 @@ export const GoogleSlidesBlock: BlockConfig<GoogleSlidesResponse> = {
|
||||
mode: 'advanced',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['read', 'write', 'replace_all_text', 'add_slide', 'add_image', 'get_thumbnail'],
|
||||
value: [
|
||||
'read',
|
||||
'write',
|
||||
'replace_all_text',
|
||||
'add_slide',
|
||||
'add_image',
|
||||
'get_thumbnail',
|
||||
'get_page',
|
||||
'delete_object',
|
||||
'duplicate_object',
|
||||
'reorder_slides',
|
||||
'create_table',
|
||||
'create_shape',
|
||||
'insert_text',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -348,6 +383,213 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
condition: { field: 'operation', value: 'get_thumbnail' },
|
||||
value: () => 'PNG',
|
||||
},
|
||||
|
||||
// ========== Get Page Operation Fields ==========
|
||||
{
|
||||
id: 'getPageObjectId',
|
||||
title: 'Page/Slide ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the slide/page to retrieve',
|
||||
condition: { field: 'operation', value: 'get_page' },
|
||||
required: true,
|
||||
},
|
||||
|
||||
// ========== Delete Object Operation Fields ==========
|
||||
{
|
||||
id: 'deleteObjectId',
|
||||
title: 'Object ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the element or slide to delete',
|
||||
condition: { field: 'operation', value: 'delete_object' },
|
||||
required: true,
|
||||
},
|
||||
|
||||
// ========== Duplicate Object Operation Fields ==========
|
||||
{
|
||||
id: 'duplicateObjectId',
|
||||
title: 'Object ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the element or slide to duplicate',
|
||||
condition: { field: 'operation', value: 'duplicate_object' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'duplicateObjectIds',
|
||||
title: 'Object ID Mappings',
|
||||
type: 'long-input',
|
||||
placeholder: 'JSON object: {"sourceId1":"newId1","sourceId2":"newId2"}',
|
||||
condition: { field: 'operation', value: 'duplicate_object' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
|
||||
// ========== Reorder Slides Operation Fields ==========
|
||||
{
|
||||
id: 'reorderSlideIds',
|
||||
title: 'Slide IDs',
|
||||
type: 'short-input',
|
||||
placeholder: 'Comma-separated slide object IDs to move',
|
||||
condition: { field: 'operation', value: 'reorder_slides' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'reorderInsertionIndex',
|
||||
title: 'New Position',
|
||||
type: 'short-input',
|
||||
placeholder: 'Zero-based index where slides should be moved',
|
||||
condition: { field: 'operation', value: 'reorder_slides' },
|
||||
required: true,
|
||||
},
|
||||
|
||||
// ========== Create Table Operation Fields ==========
|
||||
{
|
||||
id: 'tablePageObjectId',
|
||||
title: 'Slide ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the slide to add the table to',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'tableRows',
|
||||
title: 'Rows',
|
||||
type: 'short-input',
|
||||
placeholder: 'Number of rows (minimum 1)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'tableColumns',
|
||||
title: 'Columns',
|
||||
type: 'short-input',
|
||||
placeholder: 'Number of columns (minimum 1)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'tableWidth',
|
||||
title: 'Width (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Table width in points (default: 400)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
},
|
||||
{
|
||||
id: 'tableHeight',
|
||||
title: 'Height (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Table height in points (default: 200)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
},
|
||||
{
|
||||
id: 'tablePositionX',
|
||||
title: 'X Position (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'X position from left (default: 100)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
},
|
||||
{
|
||||
id: 'tablePositionY',
|
||||
title: 'Y Position (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Y position from top (default: 100)',
|
||||
condition: { field: 'operation', value: 'create_table' },
|
||||
},
|
||||
|
||||
// ========== Create Shape Operation Fields ==========
|
||||
{
|
||||
id: 'shapePageObjectId',
|
||||
title: 'Slide ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the slide to add the shape to',
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'shapeType',
|
||||
title: 'Shape Type',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Text Box', id: 'TEXT_BOX' },
|
||||
{ label: 'Rectangle', id: 'RECTANGLE' },
|
||||
{ label: 'Rounded Rectangle', id: 'ROUND_RECTANGLE' },
|
||||
{ label: 'Ellipse', id: 'ELLIPSE' },
|
||||
{ label: 'Triangle', id: 'TRIANGLE' },
|
||||
{ label: 'Diamond', id: 'DIAMOND' },
|
||||
{ label: 'Star (5 points)', id: 'STAR_5' },
|
||||
{ label: 'Arrow (Right)', id: 'RIGHT_ARROW' },
|
||||
{ label: 'Arrow (Left)', id: 'LEFT_ARROW' },
|
||||
{ label: 'Arrow (Up)', id: 'UP_ARROW' },
|
||||
{ label: 'Arrow (Down)', id: 'DOWN_ARROW' },
|
||||
{ label: 'Heart', id: 'HEART' },
|
||||
{ label: 'Cloud', id: 'CLOUD' },
|
||||
{ label: 'Lightning Bolt', id: 'LIGHTNING_BOLT' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
value: () => 'RECTANGLE',
|
||||
},
|
||||
{
|
||||
id: 'shapeWidth',
|
||||
title: 'Width (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Shape width in points (default: 200)',
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
},
|
||||
{
|
||||
id: 'shapeHeight',
|
||||
title: 'Height (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Shape height in points (default: 100)',
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
},
|
||||
{
|
||||
id: 'shapePositionX',
|
||||
title: 'X Position (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'X position from left (default: 100)',
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
},
|
||||
{
|
||||
id: 'shapePositionY',
|
||||
title: 'Y Position (points)',
|
||||
type: 'short-input',
|
||||
placeholder: 'Y position from top (default: 100)',
|
||||
condition: { field: 'operation', value: 'create_shape' },
|
||||
},
|
||||
|
||||
// ========== Insert Text Operation Fields ==========
|
||||
{
|
||||
id: 'insertTextObjectId',
|
||||
title: 'Object ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Object ID of the shape or table cell',
|
||||
condition: { field: 'operation', value: 'insert_text' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'insertTextContent',
|
||||
title: 'Text',
|
||||
type: 'long-input',
|
||||
placeholder: 'Text to insert',
|
||||
condition: { field: 'operation', value: 'insert_text' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate text content for a presentation slide based on the user's description.
|
||||
The text should be:
|
||||
- Clear and concise
|
||||
- Professional and appropriate for presentations
|
||||
- Well-structured with bullet points if listing items
|
||||
|
||||
Return ONLY the text content - no explanations, no markdown formatting markers, no extra text.`,
|
||||
placeholder: 'Describe the text you want to insert...',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'insertTextIndex',
|
||||
title: 'Insertion Index',
|
||||
type: 'short-input',
|
||||
placeholder: 'Zero-based index (default: 0)',
|
||||
condition: { field: 'operation', value: 'insert_text' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
@@ -358,6 +600,13 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
'google_slides_add_slide',
|
||||
'google_slides_add_image',
|
||||
'google_slides_get_thumbnail',
|
||||
'google_slides_get_page',
|
||||
'google_slides_delete_object',
|
||||
'google_slides_duplicate_object',
|
||||
'google_slides_update_slides_position',
|
||||
'google_slides_create_table',
|
||||
'google_slides_create_shape',
|
||||
'google_slides_insert_text',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -376,6 +625,20 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
return 'google_slides_add_image'
|
||||
case 'get_thumbnail':
|
||||
return 'google_slides_get_thumbnail'
|
||||
case 'get_page':
|
||||
return 'google_slides_get_page'
|
||||
case 'delete_object':
|
||||
return 'google_slides_delete_object'
|
||||
case 'duplicate_object':
|
||||
return 'google_slides_duplicate_object'
|
||||
case 'reorder_slides':
|
||||
return 'google_slides_update_slides_position'
|
||||
case 'create_table':
|
||||
return 'google_slides_create_table'
|
||||
case 'create_shape':
|
||||
return 'google_slides_create_shape'
|
||||
case 'insert_text':
|
||||
return 'google_slides_insert_text'
|
||||
default:
|
||||
throw new Error(`Invalid Google Slides operation: ${params.operation}`)
|
||||
}
|
||||
@@ -439,6 +702,82 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
result.pageObjectId = thumbnailPageId
|
||||
}
|
||||
|
||||
// Get Page operation
|
||||
if (params.operation === 'get_page') {
|
||||
result.pageObjectId = params.getPageObjectId
|
||||
}
|
||||
|
||||
// Delete Object operation
|
||||
if (params.operation === 'delete_object') {
|
||||
result.objectId = params.deleteObjectId
|
||||
}
|
||||
|
||||
// Duplicate Object operation
|
||||
if (params.operation === 'duplicate_object') {
|
||||
result.objectId = params.duplicateObjectId
|
||||
if (params.duplicateObjectIds) {
|
||||
result.objectIds = params.duplicateObjectIds
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder Slides operation
|
||||
if (params.operation === 'reorder_slides') {
|
||||
result.slideObjectIds = params.reorderSlideIds
|
||||
if (params.reorderInsertionIndex) {
|
||||
result.insertionIndex = Number.parseInt(params.reorderInsertionIndex as string, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Create Table operation
|
||||
if (params.operation === 'create_table') {
|
||||
result.pageObjectId = params.tablePageObjectId
|
||||
if (params.tableRows) {
|
||||
result.rows = Number.parseInt(params.tableRows as string, 10)
|
||||
}
|
||||
if (params.tableColumns) {
|
||||
result.columns = Number.parseInt(params.tableColumns as string, 10)
|
||||
}
|
||||
if (params.tableWidth) {
|
||||
result.width = Number.parseInt(params.tableWidth as string, 10)
|
||||
}
|
||||
if (params.tableHeight) {
|
||||
result.height = Number.parseInt(params.tableHeight as string, 10)
|
||||
}
|
||||
if (params.tablePositionX) {
|
||||
result.positionX = Number.parseInt(params.tablePositionX as string, 10)
|
||||
}
|
||||
if (params.tablePositionY) {
|
||||
result.positionY = Number.parseInt(params.tablePositionY as string, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Create Shape operation
|
||||
if (params.operation === 'create_shape') {
|
||||
result.pageObjectId = params.shapePageObjectId
|
||||
result.shapeType = params.shapeType
|
||||
if (params.shapeWidth) {
|
||||
result.width = Number.parseInt(params.shapeWidth as string, 10)
|
||||
}
|
||||
if (params.shapeHeight) {
|
||||
result.height = Number.parseInt(params.shapeHeight as string, 10)
|
||||
}
|
||||
if (params.shapePositionX) {
|
||||
result.positionX = Number.parseInt(params.shapePositionX as string, 10)
|
||||
}
|
||||
if (params.shapePositionY) {
|
||||
result.positionY = Number.parseInt(params.shapePositionY as string, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert Text operation
|
||||
if (params.operation === 'insert_text') {
|
||||
result.objectId = params.insertTextObjectId
|
||||
result.text = params.insertTextContent
|
||||
if (params.insertTextIndex) {
|
||||
result.insertionIndex = Number.parseInt(params.insertTextIndex as string, 10)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
@@ -479,6 +818,35 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
thumbnailPageId: { type: 'string', description: 'Slide object ID for thumbnail' },
|
||||
thumbnailSize: { type: 'string', description: 'Thumbnail size' },
|
||||
mimeType: { type: 'string', description: 'Image format (PNG or GIF)' },
|
||||
// Get page operation
|
||||
getPageObjectId: { type: 'string', description: 'Page/slide object ID to retrieve' },
|
||||
// Delete object operation
|
||||
deleteObjectId: { type: 'string', description: 'Object ID to delete' },
|
||||
// Duplicate object operation
|
||||
duplicateObjectId: { type: 'string', description: 'Object ID to duplicate' },
|
||||
duplicateObjectIds: { type: 'string', description: 'JSON object ID mappings' },
|
||||
// Reorder slides operation
|
||||
reorderSlideIds: { type: 'string', description: 'Comma-separated slide IDs to move' },
|
||||
reorderInsertionIndex: { type: 'number', description: 'New position for slides' },
|
||||
// Create table operation
|
||||
tablePageObjectId: { type: 'string', description: 'Slide ID for table' },
|
||||
tableRows: { type: 'number', description: 'Number of rows' },
|
||||
tableColumns: { type: 'number', description: 'Number of columns' },
|
||||
tableWidth: { type: 'number', description: 'Table width in points' },
|
||||
tableHeight: { type: 'number', description: 'Table height in points' },
|
||||
tablePositionX: { type: 'number', description: 'Table X position in points' },
|
||||
tablePositionY: { type: 'number', description: 'Table Y position in points' },
|
||||
// Create shape operation
|
||||
shapePageObjectId: { type: 'string', description: 'Slide ID for shape' },
|
||||
shapeType: { type: 'string', description: 'Shape type' },
|
||||
shapeWidth: { type: 'number', description: 'Shape width in points' },
|
||||
shapeHeight: { type: 'number', description: 'Shape height in points' },
|
||||
shapePositionX: { type: 'number', description: 'Shape X position in points' },
|
||||
shapePositionY: { type: 'number', description: 'Shape Y position in points' },
|
||||
// Insert text operation
|
||||
insertTextObjectId: { type: 'string', description: 'Object ID for text insertion' },
|
||||
insertTextContent: { type: 'string', description: 'Text to insert' },
|
||||
insertTextIndex: { type: 'number', description: 'Insertion index' },
|
||||
},
|
||||
outputs: {
|
||||
// Read operation
|
||||
@@ -496,5 +864,26 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
contentUrl: { type: 'string', description: 'URL to the thumbnail image' },
|
||||
width: { type: 'number', description: 'Thumbnail width in pixels' },
|
||||
height: { type: 'number', description: 'Thumbnail height in pixels' },
|
||||
// Get page operation
|
||||
objectId: { type: 'string', description: 'Page object ID' },
|
||||
pageType: { type: 'string', description: 'Page type (SLIDE, MASTER, etc.)' },
|
||||
pageElements: { type: 'json', description: 'Page elements array' },
|
||||
slideProperties: { type: 'json', description: 'Slide-specific properties' },
|
||||
// Delete object operation
|
||||
deleted: { type: 'boolean', description: 'Whether object was deleted' },
|
||||
// Duplicate object operation
|
||||
duplicatedObjectId: { type: 'string', description: 'Object ID of the duplicate' },
|
||||
// Reorder slides operation
|
||||
moved: { type: 'boolean', description: 'Whether slides were moved' },
|
||||
slideObjectIds: { type: 'json', description: 'Slide IDs that were moved' },
|
||||
// Create table operation
|
||||
tableId: { type: 'string', description: 'Object ID of newly created table' },
|
||||
rows: { type: 'number', description: 'Number of rows created' },
|
||||
columns: { type: 'number', description: 'Number of columns created' },
|
||||
// Create shape operation
|
||||
shapeId: { type: 'string', description: 'Object ID of newly created shape' },
|
||||
// Insert text operation
|
||||
inserted: { type: 'boolean', description: 'Whether text was inserted' },
|
||||
text: { type: 'string', description: 'Text that was inserted' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { MicrosoftExcelIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { MicrosoftExcelResponse } from '@/tools/microsoft_excel/types'
|
||||
import type {
|
||||
MicrosoftExcelResponse,
|
||||
MicrosoftExcelV2Response,
|
||||
} from '@/tools/microsoft_excel/types'
|
||||
|
||||
export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
|
||||
type: 'microsoft_excel',
|
||||
@@ -325,3 +328,260 @@ Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const MicrosoftExcelV2Block: BlockConfig<MicrosoftExcelV2Response> = {
|
||||
type: 'microsoft_excel_v2',
|
||||
name: 'Microsoft Excel',
|
||||
description: 'Read and write data with sheet selection',
|
||||
authMode: AuthMode.OAuth,
|
||||
hideFromToolbar: false,
|
||||
longDescription:
|
||||
'Integrate Microsoft Excel into the workflow with explicit sheet selection. Can read and write data in specific sheets.',
|
||||
docsLink: 'https://docs.sim.ai/tools/microsoft_excel',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: MicrosoftExcelIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Read Data', id: 'read' },
|
||||
{ label: 'Write Data', id: 'write' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
// Microsoft Excel Credentials
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Microsoft Account',
|
||||
type: 'oauth-input',
|
||||
serviceId: 'microsoft-excel',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'Files.Read',
|
||||
'Files.ReadWrite',
|
||||
'offline_access',
|
||||
],
|
||||
placeholder: 'Select Microsoft account',
|
||||
required: true,
|
||||
},
|
||||
// Spreadsheet Selector (basic mode)
|
||||
{
|
||||
id: 'spreadsheetId',
|
||||
title: 'Select Spreadsheet',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'microsoft-excel',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Spreadsheet ID (advanced mode)
|
||||
{
|
||||
id: 'manualSpreadsheetId',
|
||||
title: 'Spreadsheet ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
placeholder: 'Enter spreadsheet ID',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Sheet Name Selector (basic mode)
|
||||
{
|
||||
id: 'sheetName',
|
||||
title: 'Sheet (Tab)',
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'microsoft-excel',
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Sheet Name (advanced mode)
|
||||
{
|
||||
id: 'manualSheetName',
|
||||
title: 'Sheet Name',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'sheetName',
|
||||
placeholder: 'Name of the sheet/tab (e.g., Sheet1)',
|
||||
required: true,
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Cell Range (optional for read/write)
|
||||
{
|
||||
id: 'cellRange',
|
||||
title: 'Cell Range',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cell range (e.g., A1:D10). Defaults to used range for read, A1 for write.',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a valid cell range based on the user's description.
|
||||
|
||||
### VALID FORMATS
|
||||
- Single cell: A1
|
||||
- Range: A1:D10
|
||||
- Entire column: A:A
|
||||
- Entire row: 1:1
|
||||
- Multiple columns: A:D
|
||||
- Multiple rows: 1:10
|
||||
|
||||
### RANGE RULES
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB, etc.
|
||||
- Row numbers start at 1 (not 0)
|
||||
|
||||
### EXAMPLES
|
||||
- "first 100 rows" -> A1:Z100
|
||||
- "cells A1 through C50" -> A1:C50
|
||||
- "column A" -> A:A
|
||||
- "just the headers row" -> 1:1
|
||||
- "first cell" -> A1
|
||||
|
||||
Return ONLY the range string - no sheet name, no explanations, no quotes.`,
|
||||
placeholder: 'Describe the range (e.g., "first 50 rows" or "column A")...',
|
||||
},
|
||||
},
|
||||
// Write-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects (e.g., [{"name":"John", "age":30}])',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Microsoft Excel data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "sales data with product and revenue columns" -> [["Product", "Revenue"], ["Widget A", 1500], ["Widget B", 2300]]
|
||||
- "list of employees with name and email" -> [{"name": "John Doe", "email": "john@example.com"}, {"name": "Jane Smith", "email": "jane@example.com"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to write...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: ['microsoft_excel_read_v2', 'microsoft_excel_write_v2'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'read':
|
||||
return 'microsoft_excel_read_v2'
|
||||
case 'write':
|
||||
return 'microsoft_excel_write_v2'
|
||||
default:
|
||||
throw new Error(`Invalid Microsoft Excel V2 operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const {
|
||||
credential,
|
||||
values,
|
||||
spreadsheetId,
|
||||
manualSpreadsheetId,
|
||||
sheetName,
|
||||
manualSheetName,
|
||||
cellRange,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const parsedValues = values ? JSON.parse(values as string) : undefined
|
||||
|
||||
const effectiveSpreadsheetId = (spreadsheetId || manualSpreadsheetId || '').trim()
|
||||
const effectiveSheetName = ((sheetName || manualSheetName || '') as string).trim()
|
||||
|
||||
if (!effectiveSpreadsheetId) {
|
||||
throw new Error('Spreadsheet ID is required.')
|
||||
}
|
||||
|
||||
if (!effectiveSheetName) {
|
||||
throw new Error('Sheet name is required. Please select or enter a sheet name.')
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
sheetName: effectiveSheetName,
|
||||
cellRange: cellRange ? (cellRange as string).trim() : undefined,
|
||||
values: parsedValues,
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Microsoft Excel access token' },
|
||||
spreadsheetId: { type: 'string', description: 'Spreadsheet identifier' },
|
||||
manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' },
|
||||
sheetName: { type: 'string', description: 'Name of the sheet/tab' },
|
||||
manualSheetName: { type: 'string', description: 'Manual sheet name entry' },
|
||||
cellRange: { type: 'string', description: 'Cell range (e.g., A1:D10)' },
|
||||
values: { type: 'string', description: 'Cell values data' },
|
||||
valueInputOption: { type: 'string', description: 'Value input option' },
|
||||
},
|
||||
outputs: {
|
||||
sheetName: {
|
||||
type: 'string',
|
||||
description: 'Name of the sheet',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
range: {
|
||||
type: 'string',
|
||||
description: 'Range that was read',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
values: {
|
||||
type: 'json',
|
||||
description: 'Cell values as 2D array',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
updatedRange: {
|
||||
type: 'string',
|
||||
description: 'Updated range',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedRows: {
|
||||
type: 'number',
|
||||
description: 'Updated rows count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedColumns: {
|
||||
type: 'number',
|
||||
description: 'Updated columns count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedCells: {
|
||||
type: 'number',
|
||||
description: 'Updated cells count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
metadata: { type: 'json', description: 'Spreadsheet metadata including ID and URL' },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
import { MicrosoftExcelIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
import type { MicrosoftExcelV2Response } from '@/tools/microsoft_excel/types'
|
||||
|
||||
export const MicrosoftExcelV2Block: BlockConfig<MicrosoftExcelV2Response> = {
|
||||
type: 'microsoft_excel_v2',
|
||||
name: 'Microsoft Excel',
|
||||
description: 'Read and write data with sheet selection',
|
||||
authMode: AuthMode.OAuth,
|
||||
hideFromToolbar: false,
|
||||
longDescription:
|
||||
'Integrate Microsoft Excel into the workflow with explicit sheet selection. Can read and write data in specific sheets.',
|
||||
docsLink: 'https://docs.sim.ai/tools/microsoft_excel',
|
||||
category: 'tools',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: MicrosoftExcelIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Read Data', id: 'read' },
|
||||
{ label: 'Write Data', id: 'write' },
|
||||
],
|
||||
value: () => 'read',
|
||||
},
|
||||
// Microsoft Excel Credentials
|
||||
{
|
||||
id: 'credential',
|
||||
title: 'Microsoft Account',
|
||||
type: 'oauth-input',
|
||||
serviceId: 'microsoft-excel',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'Files.Read',
|
||||
'Files.ReadWrite',
|
||||
'offline_access',
|
||||
],
|
||||
placeholder: 'Select Microsoft account',
|
||||
required: true,
|
||||
},
|
||||
// Spreadsheet Selector (basic mode)
|
||||
{
|
||||
id: 'spreadsheetId',
|
||||
title: 'Select Spreadsheet',
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'microsoft-excel',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Spreadsheet ID (advanced mode)
|
||||
{
|
||||
id: 'manualSpreadsheetId',
|
||||
title: 'Spreadsheet ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
placeholder: 'Enter spreadsheet ID',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Sheet Name Selector (basic mode)
|
||||
{
|
||||
id: 'sheetName',
|
||||
title: 'Sheet (Tab)',
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'microsoft-excel',
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
mode: 'basic',
|
||||
},
|
||||
// Manual Sheet Name (advanced mode)
|
||||
{
|
||||
id: 'manualSheetName',
|
||||
title: 'Sheet Name',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'sheetName',
|
||||
placeholder: 'Name of the sheet/tab (e.g., Sheet1)',
|
||||
required: true,
|
||||
dependsOn: ['credential'],
|
||||
mode: 'advanced',
|
||||
},
|
||||
// Cell Range (optional for read/write)
|
||||
{
|
||||
id: 'cellRange',
|
||||
title: 'Cell Range',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cell range (e.g., A1:D10). Defaults to used range for read, A1 for write.',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate a valid cell range based on the user's description.
|
||||
|
||||
### VALID FORMATS
|
||||
- Single cell: A1
|
||||
- Range: A1:D10
|
||||
- Entire column: A:A
|
||||
- Entire row: 1:1
|
||||
- Multiple columns: A:D
|
||||
- Multiple rows: 1:10
|
||||
|
||||
### RANGE RULES
|
||||
- Column letters are uppercase: A, B, C, ... Z, AA, AB, etc.
|
||||
- Row numbers start at 1 (not 0)
|
||||
|
||||
### EXAMPLES
|
||||
- "first 100 rows" -> A1:Z100
|
||||
- "cells A1 through C50" -> A1:C50
|
||||
- "column A" -> A:A
|
||||
- "just the headers row" -> 1:1
|
||||
- "first cell" -> A1
|
||||
|
||||
Return ONLY the range string - no sheet name, no explanations, no quotes.`,
|
||||
placeholder: 'Describe the range (e.g., "first 50 rows" or "column A")...',
|
||||
},
|
||||
},
|
||||
// Write-specific Fields
|
||||
{
|
||||
id: 'values',
|
||||
title: 'Values',
|
||||
type: 'long-input',
|
||||
placeholder:
|
||||
'Enter values as JSON array of arrays (e.g., [["A1", "B1"], ["A2", "B2"]]) or an array of objects (e.g., [{"name":"John", "age":30}])',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
required: true,
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
prompt: `Generate Microsoft Excel data as a JSON array based on the user's description.
|
||||
|
||||
Format options:
|
||||
1. Array of arrays: [["Header1", "Header2"], ["Value1", "Value2"]]
|
||||
2. Array of objects: [{"column1": "value1", "column2": "value2"}]
|
||||
|
||||
Examples:
|
||||
- "sales data with product and revenue columns" -> [["Product", "Revenue"], ["Widget A", 1500], ["Widget B", 2300]]
|
||||
- "list of employees with name and email" -> [{"name": "John Doe", "email": "john@example.com"}, {"name": "Jane Smith", "email": "jane@example.com"}]
|
||||
|
||||
Return ONLY the JSON array - no explanations, no markdown, no extra text.`,
|
||||
placeholder: 'Describe the data you want to write...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'valueInputOption',
|
||||
title: 'Value Input Option',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'User Entered (Parse formulas)', id: 'USER_ENTERED' },
|
||||
{ label: "Raw (Don't parse formulas)", id: 'RAW' },
|
||||
],
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: ['microsoft_excel_read_v2', 'microsoft_excel_write_v2'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
switch (params.operation) {
|
||||
case 'read':
|
||||
return 'microsoft_excel_read_v2'
|
||||
case 'write':
|
||||
return 'microsoft_excel_write_v2'
|
||||
default:
|
||||
throw new Error(`Invalid Microsoft Excel V2 operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const {
|
||||
credential,
|
||||
values,
|
||||
spreadsheetId,
|
||||
manualSpreadsheetId,
|
||||
sheetName,
|
||||
manualSheetName,
|
||||
cellRange,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
const parsedValues = values ? JSON.parse(values as string) : undefined
|
||||
|
||||
const effectiveSpreadsheetId = (spreadsheetId || manualSpreadsheetId || '').trim()
|
||||
const effectiveSheetName = ((sheetName || manualSheetName || '') as string).trim()
|
||||
|
||||
if (!effectiveSpreadsheetId) {
|
||||
throw new Error('Spreadsheet ID is required.')
|
||||
}
|
||||
|
||||
if (!effectiveSheetName) {
|
||||
throw new Error('Sheet name is required. Please select or enter a sheet name.')
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
spreadsheetId: effectiveSpreadsheetId,
|
||||
sheetName: effectiveSheetName,
|
||||
cellRange: cellRange ? (cellRange as string).trim() : undefined,
|
||||
values: parsedValues,
|
||||
credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
credential: { type: 'string', description: 'Microsoft Excel access token' },
|
||||
spreadsheetId: { type: 'string', description: 'Spreadsheet identifier' },
|
||||
manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' },
|
||||
sheetName: { type: 'string', description: 'Name of the sheet/tab' },
|
||||
manualSheetName: { type: 'string', description: 'Manual sheet name entry' },
|
||||
cellRange: { type: 'string', description: 'Cell range (e.g., A1:D10)' },
|
||||
values: { type: 'string', description: 'Cell values data' },
|
||||
valueInputOption: { type: 'string', description: 'Value input option' },
|
||||
},
|
||||
outputs: {
|
||||
sheetName: {
|
||||
type: 'string',
|
||||
description: 'Name of the sheet',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
range: {
|
||||
type: 'string',
|
||||
description: 'Range that was read',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
values: {
|
||||
type: 'json',
|
||||
description: 'Cell values as 2D array',
|
||||
condition: { field: 'operation', value: 'read' },
|
||||
},
|
||||
updatedRange: {
|
||||
type: 'string',
|
||||
description: 'Updated range',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedRows: {
|
||||
type: 'number',
|
||||
description: 'Updated rows count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedColumns: {
|
||||
type: 'number',
|
||||
description: 'Updated columns count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
updatedCells: {
|
||||
type: 'number',
|
||||
description: 'Updated cells count',
|
||||
condition: { field: 'operation', value: 'write' },
|
||||
},
|
||||
metadata: { type: 'json', description: 'Spreadsheet metadata including ID and URL' },
|
||||
},
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import { ApifyBlock } from '@/blocks/blocks/apify'
|
||||
import { ApolloBlock } from '@/blocks/blocks/apollo'
|
||||
import { ArxivBlock } from '@/blocks/blocks/arxiv'
|
||||
import { AsanaBlock } from '@/blocks/blocks/asana'
|
||||
// import { BoxBlock } from '@/blocks/blocks/box' // TODO: Box OAuth integration
|
||||
import { BrowserUseBlock } from '@/blocks/blocks/browser_use'
|
||||
import { CalendlyBlock } from '@/blocks/blocks/calendly'
|
||||
import { ChatTriggerBlock } from '@/blocks/blocks/chat_trigger'
|
||||
@@ -38,10 +37,9 @@ import { GoogleSearchBlock } from '@/blocks/blocks/google'
|
||||
import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar'
|
||||
import { GoogleDocsBlock } from '@/blocks/blocks/google_docs'
|
||||
import { GoogleDriveBlock } from '@/blocks/blocks/google_drive'
|
||||
import { GoogleFormsBlock } from '@/blocks/blocks/google_form'
|
||||
import { GoogleFormsBlock } from '@/blocks/blocks/google_forms'
|
||||
import { GoogleGroupsBlock } from '@/blocks/blocks/google_groups'
|
||||
import { GoogleSheetsBlock } from '@/blocks/blocks/google_sheets'
|
||||
import { GoogleSheetsV2Block } from '@/blocks/blocks/google_sheets_v2'
|
||||
import { GoogleSheetsBlock, GoogleSheetsV2Block } from '@/blocks/blocks/google_sheets'
|
||||
import { GoogleSlidesBlock } from '@/blocks/blocks/google_slides'
|
||||
import { GoogleVaultBlock } from '@/blocks/blocks/google_vault'
|
||||
import { GrafanaBlock } from '@/blocks/blocks/grafana'
|
||||
@@ -73,8 +71,7 @@ import { ManualTriggerBlock } from '@/blocks/blocks/manual_trigger'
|
||||
import { McpBlock } from '@/blocks/blocks/mcp'
|
||||
import { Mem0Block } from '@/blocks/blocks/mem0'
|
||||
import { MemoryBlock } from '@/blocks/blocks/memory'
|
||||
import { MicrosoftExcelBlock } from '@/blocks/blocks/microsoft_excel'
|
||||
import { MicrosoftExcelV2Block } from '@/blocks/blocks/microsoft_excel_v2'
|
||||
import { MicrosoftExcelBlock, MicrosoftExcelV2Block } from '@/blocks/blocks/microsoft_excel'
|
||||
import { MicrosoftPlannerBlock } from '@/blocks/blocks/microsoft_planner'
|
||||
import { MicrosoftTeamsBlock } from '@/blocks/blocks/microsoft_teams'
|
||||
import { MistralParseBlock } from '@/blocks/blocks/mistral_parse'
|
||||
@@ -116,6 +113,7 @@ 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 { SQSBlock } from '@/blocks/blocks/sqs'
|
||||
import { SSHBlock } from '@/blocks/blocks/ssh'
|
||||
import { StagehandBlock } from '@/blocks/blocks/stagehand'
|
||||
import { StartTriggerBlock } from '@/blocks/blocks/start_trigger'
|
||||
@@ -151,7 +149,6 @@ 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<string, BlockConfig> = {
|
||||
@@ -165,7 +162,6 @@ export const registry: Record<string, BlockConfig> = {
|
||||
apollo: ApolloBlock,
|
||||
arxiv: ArxivBlock,
|
||||
asana: AsanaBlock,
|
||||
// box: BoxBlock, // TODO: Box OAuth integration
|
||||
browser_use: BrowserUseBlock,
|
||||
calendly: CalendlyBlock,
|
||||
chat_trigger: ChatTriggerBlock,
|
||||
@@ -179,8 +175,9 @@ export const registry: Record<string, BlockConfig> = {
|
||||
discord: DiscordBlock,
|
||||
dropbox: DropboxBlock,
|
||||
duckduckgo: DuckDuckGoBlock,
|
||||
elevenlabs: ElevenLabsBlock,
|
||||
dynamodb: DynamoDBBlock,
|
||||
elasticsearch: ElasticsearchBlock,
|
||||
elevenlabs: ElevenLabsBlock,
|
||||
evaluator: EvaluatorBlock,
|
||||
exa: ExaBlock,
|
||||
file: FileBlock,
|
||||
@@ -193,21 +190,21 @@ export const registry: Record<string, BlockConfig> = {
|
||||
gitlab: GitLabBlock,
|
||||
gmail: GmailBlock,
|
||||
gmail_v2: GmailV2Block,
|
||||
grain: GrainBlock,
|
||||
grafana: GrafanaBlock,
|
||||
greptile: GreptileBlock,
|
||||
guardrails: GuardrailsBlock,
|
||||
google_calendar: GoogleCalendarBlock,
|
||||
google_calendar_v2: GoogleCalendarV2Block,
|
||||
google_docs: GoogleDocsBlock,
|
||||
google_drive: GoogleDriveBlock,
|
||||
google_forms: GoogleFormsBlock,
|
||||
google_groups: GoogleGroupsBlock,
|
||||
google_search: GoogleSearchBlock,
|
||||
google_sheets: GoogleSheetsBlock,
|
||||
google_sheets_v2: GoogleSheetsV2Block,
|
||||
google_slides: GoogleSlidesBlock,
|
||||
google_vault: GoogleVaultBlock,
|
||||
google_groups: GoogleGroupsBlock,
|
||||
grafana: GrafanaBlock,
|
||||
grain: GrainBlock,
|
||||
greptile: GreptileBlock,
|
||||
guardrails: GuardrailsBlock,
|
||||
hubspot: HubSpotBlock,
|
||||
huggingface: HuggingFaceBlock,
|
||||
human_in_the_loop: HumanInTheLoopBlock,
|
||||
@@ -239,7 +236,6 @@ export const registry: Record<string, BlockConfig> = {
|
||||
microsoft_planner: MicrosoftPlannerBlock,
|
||||
microsoft_teams: MicrosoftTeamsBlock,
|
||||
mistral_parse: MistralParseBlock,
|
||||
reducto: ReductoBlock,
|
||||
mongodb: MongoDBBlock,
|
||||
mysql: MySQLBlock,
|
||||
neo4j: Neo4jBlock,
|
||||
@@ -259,35 +255,34 @@ export const registry: Record<string, BlockConfig> = {
|
||||
pulse: PulseBlock,
|
||||
qdrant: QdrantBlock,
|
||||
rds: RDSBlock,
|
||||
sqs: SQSBlock,
|
||||
dynamodb: DynamoDBBlock,
|
||||
reddit: RedditBlock,
|
||||
reducto: ReductoBlock,
|
||||
resend: ResendBlock,
|
||||
response: ResponseBlock,
|
||||
rss: RssBlock,
|
||||
router: RouterBlock,
|
||||
router_v2: RouterV2Block,
|
||||
rss: RssBlock,
|
||||
s3: S3Block,
|
||||
salesforce: SalesforceBlock,
|
||||
schedule: ScheduleBlock,
|
||||
search: SearchBlock,
|
||||
sendgrid: SendGridBlock,
|
||||
sentry: SentryBlock,
|
||||
servicenow: ServiceNowBlock,
|
||||
serper: SerperBlock,
|
||||
servicenow: ServiceNowBlock,
|
||||
sftp: SftpBlock,
|
||||
sharepoint: SharepointBlock,
|
||||
shopify: ShopifyBlock,
|
||||
slack: SlackBlock,
|
||||
spotify: SpotifyBlock,
|
||||
smtp: SmtpBlock,
|
||||
sftp: SftpBlock,
|
||||
spotify: SpotifyBlock,
|
||||
sqs: SQSBlock,
|
||||
ssh: SSHBlock,
|
||||
stagehand: StagehandBlock,
|
||||
starter: StarterBlock,
|
||||
start_trigger: StartTriggerBlock,
|
||||
stt: SttBlock,
|
||||
tts: TtsBlock,
|
||||
starter: StarterBlock,
|
||||
stripe: StripeBlock,
|
||||
stt: SttBlock,
|
||||
supabase: SupabaseBlock,
|
||||
tavily: TavilyBlock,
|
||||
telegram: TelegramBlock,
|
||||
@@ -295,6 +290,7 @@ export const registry: Record<string, BlockConfig> = {
|
||||
tinybird: TinybirdBlock,
|
||||
translate: TranslateBlock,
|
||||
trello: TrelloBlock,
|
||||
tts: TtsBlock,
|
||||
twilio_sms: TwilioSMSBlock,
|
||||
twilio_voice: TwilioVoiceBlock,
|
||||
typeform: TypeformBlock,
|
||||
@@ -312,8 +308,8 @@ export const registry: Record<string, BlockConfig> = {
|
||||
workflow_input: WorkflowInputBlock,
|
||||
x: XBlock,
|
||||
youtube: YouTubeBlock,
|
||||
zep: ZepBlock,
|
||||
zendesk: ZendeskBlock,
|
||||
zep: ZepBlock,
|
||||
zoom: ZoomBlock,
|
||||
}
|
||||
|
||||
|
||||
@@ -587,9 +587,14 @@ const Combobox = memo(
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
setOpen(false)
|
||||
setSearchQuery('')
|
||||
// Forward navigation keys to main handler
|
||||
if (
|
||||
e.key === 'ArrowDown' ||
|
||||
e.key === 'ArrowUp' ||
|
||||
e.key === 'Enter' ||
|
||||
e.key === 'Escape'
|
||||
) {
|
||||
handleKeyDown(e as unknown as KeyboardEvent<HTMLDivElement>)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -11,15 +11,18 @@ export const a2aCancelTaskTool: ToolConfig<A2ACancelTaskParams, A2ACancelTaskRes
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to cancel',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,20 +14,24 @@ export const a2aDeletePushNotificationTool: ToolConfig<
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to delete notification config for',
|
||||
},
|
||||
pushNotificationConfigId: {
|
||||
type: 'string',
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Push notification configuration ID to delete (optional - server can derive from taskId)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,10 +11,12 @@ export const a2aGetAgentCardTool: ToolConfig<A2AGetAgentCardParams, A2AGetAgentC
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication (if required)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,15 +14,18 @@ export const a2aGetPushNotificationTool: ToolConfig<
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to get notification config for',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,19 +11,23 @@ export const a2aGetTaskTool: ToolConfig<A2AGetTaskParams, A2AGetTaskResponse> =
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to query',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
historyLength: {
|
||||
type: 'number',
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of history messages to include',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,15 +11,18 @@ export const a2aResubscribeTool: ToolConfig<A2AResubscribeParams, A2AResubscribe
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to resubscribe to',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,31 +11,38 @@ export const a2aSendMessageTool: ToolConfig<A2ASendMessageParams, A2ASendMessage
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Message to send to the agent',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID for continuing an existing task',
|
||||
},
|
||||
contextId: {
|
||||
type: 'string',
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Context ID for conversation continuity',
|
||||
},
|
||||
data: {
|
||||
type: 'string',
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Structured data to include with the message (JSON string)',
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
visibility: 'user-only',
|
||||
description: 'Files to include with the message',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,24 +14,29 @@ export const a2aSetPushNotificationTool: ToolConfig<
|
||||
agentUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'The A2A agent endpoint URL',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task ID to configure notifications for',
|
||||
},
|
||||
webhookUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'HTTPS webhook URL to receive notifications',
|
||||
},
|
||||
token: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'Token for webhook validation',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
visibility: 'user-only',
|
||||
description: 'API key for authentication',
|
||||
},
|
||||
},
|
||||
|
||||
115
apps/sim/tools/github/check_star.ts
Normal file
115
apps/sim/tools/github/check_star.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CheckStarParams {
|
||||
owner: string
|
||||
repo: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CheckStarResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
starred: boolean
|
||||
owner: string
|
||||
repo: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const checkStarTool: ToolConfig<CheckStarParams, CheckStarResponse> = {
|
||||
id: 'github_check_star',
|
||||
name: 'GitHub Check Star',
|
||||
description: 'Check if you have starred a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/user/starred/${params.owner}/${params.repo}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const starred = response.status === 204
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: starred
|
||||
? `You have starred ${params?.owner}/${params?.repo}`
|
||||
: `You have not starred ${params?.owner}/${params?.repo}`,
|
||||
metadata: {
|
||||
starred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Check star metadata',
|
||||
properties: {
|
||||
starred: { type: 'boolean', description: 'Whether you have starred the repo' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const checkStarV2Tool: ToolConfig<CheckStarParams, any> = {
|
||||
id: 'github_check_star_v2',
|
||||
name: checkStarTool.name,
|
||||
description: checkStarTool.description,
|
||||
version: '2.0.0',
|
||||
params: checkStarTool.params,
|
||||
request: checkStarTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const starred = response.status === 204
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
starred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
starred: { type: 'boolean', description: 'Whether you have starred the repo' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
}
|
||||
256
apps/sim/tools/github/compare_commits.ts
Normal file
256
apps/sim/tools/github/compare_commits.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CompareCommitsParams {
|
||||
owner: string
|
||||
repo: string
|
||||
base: string
|
||||
head: string
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CompareCommitsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
status: string
|
||||
ahead_by: number
|
||||
behind_by: number
|
||||
total_commits: number
|
||||
html_url: string
|
||||
diff_url: string
|
||||
patch_url: string
|
||||
base_commit: { sha: string; html_url: string }
|
||||
merge_base_commit: { sha: string; html_url: string }
|
||||
commits: Array<{
|
||||
sha: string
|
||||
html_url: string
|
||||
message: string
|
||||
author: { login?: string; name: string }
|
||||
}>
|
||||
files: Array<{
|
||||
filename: string
|
||||
status: string
|
||||
additions: number
|
||||
deletions: number
|
||||
changes: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const compareCommitsTool: ToolConfig<CompareCommitsParams, CompareCommitsResponse> = {
|
||||
id: 'github_compare_commits',
|
||||
name: 'GitHub Compare Commits',
|
||||
description:
|
||||
'Compare two commits or branches to see the diff, commits between them, and changed files',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
base: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Base branch/tag/SHA for comparison',
|
||||
},
|
||||
head: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Head branch/tag/SHA for comparison',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page for files (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for files (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/compare/${params.base}...${params.head}`
|
||||
)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const commits = (data.commits ?? []).map((c: any) => ({
|
||||
sha: c.sha,
|
||||
html_url: c.html_url,
|
||||
message: c.commit.message,
|
||||
author: {
|
||||
login: c.author?.login,
|
||||
name: c.commit.author.name,
|
||||
},
|
||||
}))
|
||||
|
||||
const files = (data.files ?? []).map((f: any) => ({
|
||||
filename: f.filename,
|
||||
status: f.status,
|
||||
additions: f.additions,
|
||||
deletions: f.deletions,
|
||||
changes: f.changes,
|
||||
}))
|
||||
|
||||
const metadata = {
|
||||
status: data.status,
|
||||
ahead_by: data.ahead_by,
|
||||
behind_by: data.behind_by,
|
||||
total_commits: data.total_commits,
|
||||
html_url: data.html_url,
|
||||
diff_url: data.diff_url,
|
||||
patch_url: data.patch_url,
|
||||
base_commit: {
|
||||
sha: data.base_commit.sha,
|
||||
html_url: data.base_commit.html_url,
|
||||
},
|
||||
merge_base_commit: {
|
||||
sha: data.merge_base_commit.sha,
|
||||
html_url: data.merge_base_commit.html_url,
|
||||
},
|
||||
commits,
|
||||
files,
|
||||
}
|
||||
|
||||
const content = `Comparing ${data.base_commit.sha.substring(0, 7)}...${data.commits?.length > 0 ? data.commits[data.commits.length - 1].sha.substring(0, 7) : 'HEAD'}
|
||||
Status: ${data.status} | Ahead: ${data.ahead_by} | Behind: ${data.behind_by}
|
||||
Total commits: ${data.total_commits} | Files changed: ${files.length}
|
||||
${data.html_url}
|
||||
|
||||
Commits:
|
||||
${commits.map((c: any) => ` ${c.sha.substring(0, 7)} - ${c.message.split('\n')[0]}`).join('\n')}
|
||||
|
||||
Files changed:
|
||||
${files.map((f: any) => ` ${f.status}: ${f.filename} (+${f.additions} -${f.deletions})`).join('\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable comparison' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Comparison metadata',
|
||||
properties: {
|
||||
status: { type: 'string', description: 'ahead, behind, identical, or diverged' },
|
||||
ahead_by: { type: 'number', description: 'Commits ahead' },
|
||||
behind_by: { type: 'number', description: 'Commits behind' },
|
||||
total_commits: { type: 'number', description: 'Total commits between' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
diff_url: { type: 'string', description: 'Diff URL' },
|
||||
patch_url: { type: 'string', description: 'Patch URL' },
|
||||
base_commit: { type: 'object', description: 'Base commit info' },
|
||||
merge_base_commit: { type: 'object', description: 'Merge base commit info' },
|
||||
commits: {
|
||||
type: 'array',
|
||||
description: 'Commits between base and head',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
message: { type: 'string', description: 'Commit message' },
|
||||
author: { type: 'object', description: 'Author info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
description: 'Changed files',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
filename: { type: 'string', description: 'File path' },
|
||||
status: { type: 'string', description: 'Change type' },
|
||||
additions: { type: 'number', description: 'Lines added' },
|
||||
deletions: { type: 'number', description: 'Lines deleted' },
|
||||
changes: { type: 'number', description: 'Total changes' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const compareCommitsV2Tool: ToolConfig<CompareCommitsParams, any> = {
|
||||
id: 'github_compare_commits_v2',
|
||||
name: compareCommitsTool.name,
|
||||
description: compareCommitsTool.description,
|
||||
version: '2.0.0',
|
||||
params: compareCommitsTool.params,
|
||||
request: compareCommitsTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
commits: data.commits ?? [],
|
||||
files: data.files ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
status: { type: 'string', description: 'Comparison status' },
|
||||
ahead_by: { type: 'number', description: 'Commits ahead' },
|
||||
behind_by: { type: 'number', description: 'Commits behind' },
|
||||
total_commits: { type: 'number', description: 'Total commits' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
diff_url: { type: 'string', description: 'Diff URL' },
|
||||
patch_url: { type: 'string', description: 'Patch URL' },
|
||||
base_commit: { type: 'object', description: 'Base commit' },
|
||||
merge_base_commit: { type: 'object', description: 'Merge base' },
|
||||
commits: { type: 'array', description: 'Commits between' },
|
||||
files: { type: 'array', description: 'Changed files' },
|
||||
},
|
||||
}
|
||||
138
apps/sim/tools/github/create_comment_reaction.ts
Normal file
138
apps/sim/tools/github/create_comment_reaction.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CreateCommentReactionParams {
|
||||
owner: string
|
||||
repo: string
|
||||
comment_id: number
|
||||
content: '+1' | '-1' | 'laugh' | 'confused' | 'heart' | 'hooray' | 'rocket' | 'eyes'
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CreateCommentReactionResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: number
|
||||
user: { login: string }
|
||||
content: string
|
||||
created_at: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createCommentReactionTool: ToolConfig<
|
||||
CreateCommentReactionParams,
|
||||
CreateCommentReactionResponse
|
||||
> = {
|
||||
id: 'github_create_comment_reaction',
|
||||
name: 'GitHub Create Comment Reaction',
|
||||
description: 'Add a reaction to an issue comment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
comment_id: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment ID',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Reaction type: +1 (thumbs up), -1 (thumbs down), laugh, confused, heart, hooray, rocket, eyes',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/issues/comments/${params.comment_id}/reactions`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.squirrel-girl-preview+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => ({
|
||||
content: params.content,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const content = `Added ${data.content} reaction to comment by ${data.user?.login ?? 'unknown'}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
user: { login: data.user?.login ?? 'unknown' },
|
||||
content: data.content,
|
||||
created_at: data.created_at,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Reaction metadata',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Reaction ID' },
|
||||
user: { type: 'object', description: 'User who reacted' },
|
||||
content: { type: 'string', description: 'Reaction type' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const createCommentReactionV2Tool: ToolConfig<CreateCommentReactionParams, any> = {
|
||||
id: 'github_create_comment_reaction_v2',
|
||||
name: createCommentReactionTool.name,
|
||||
description: createCommentReactionTool.description,
|
||||
version: '2.0.0',
|
||||
params: createCommentReactionTool.params,
|
||||
request: createCommentReactionTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'number', description: 'Reaction ID' },
|
||||
user: { type: 'object', description: 'User who reacted' },
|
||||
content: { type: 'string', description: 'Reaction type' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
},
|
||||
}
|
||||
183
apps/sim/tools/github/create_gist.ts
Normal file
183
apps/sim/tools/github/create_gist.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CreateGistParams {
|
||||
description?: string
|
||||
files: string
|
||||
public?: boolean
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CreateGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: string
|
||||
html_url: string
|
||||
git_pull_url: string
|
||||
git_push_url: string
|
||||
description: string | null
|
||||
public: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number }
|
||||
>
|
||||
owner: { login: string }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createGistTool: ToolConfig<CreateGistParams, CreateGistResponse> = {
|
||||
id: 'github_create_gist',
|
||||
name: 'GitHub Create Gist',
|
||||
description: 'Create a new gist with one or more files',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Description of the gist',
|
||||
},
|
||||
files: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON object with filenames as keys and content as values. Example: {"file.txt": {"content": "Hello"}}',
|
||||
},
|
||||
public: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the gist is public (default: false)',
|
||||
default: false,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: () => 'https://api.github.com/gists',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => {
|
||||
const filesObj = typeof params.files === 'string' ? JSON.parse(params.files) : params.files
|
||||
return {
|
||||
description: params.description,
|
||||
public: params.public ?? false,
|
||||
files: filesObj,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number }
|
||||
> = {}
|
||||
for (const [key, value] of Object.entries(data.files ?? {})) {
|
||||
const file = value as any
|
||||
files[key] = {
|
||||
filename: file.filename,
|
||||
type: file.type,
|
||||
language: file.language ?? null,
|
||||
size: file.size,
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
id: data.id,
|
||||
html_url: data.html_url,
|
||||
git_pull_url: data.git_pull_url,
|
||||
git_push_url: data.git_push_url,
|
||||
description: data.description ?? null,
|
||||
public: data.public,
|
||||
created_at: data.created_at,
|
||||
updated_at: data.updated_at,
|
||||
files,
|
||||
owner: { login: data.owner?.login ?? 'unknown' },
|
||||
}
|
||||
|
||||
const content = `Created gist: ${data.html_url}
|
||||
Description: ${data.description ?? 'No description'}
|
||||
Public: ${data.public}
|
||||
Files: ${Object.keys(files).join(', ')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Gist metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
git_pull_url: { type: 'string', description: 'Git pull URL' },
|
||||
git_push_url: { type: 'string', description: 'Git push URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Files in gist' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const createGistV2Tool: ToolConfig<CreateGistParams, any> = {
|
||||
id: 'github_create_gist_v2',
|
||||
name: createGistTool.name,
|
||||
description: createGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: createGistTool.params,
|
||||
request: createGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
files: data.files ?? {},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
git_pull_url: { type: 'string', description: 'Git pull URL' },
|
||||
git_push_url: { type: 'string', description: 'Git push URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Files in gist' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
},
|
||||
}
|
||||
138
apps/sim/tools/github/create_issue_reaction.ts
Normal file
138
apps/sim/tools/github/create_issue_reaction.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CreateIssueReactionParams {
|
||||
owner: string
|
||||
repo: string
|
||||
issue_number: number
|
||||
content: '+1' | '-1' | 'laugh' | 'confused' | 'heart' | 'hooray' | 'rocket' | 'eyes'
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CreateIssueReactionResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: number
|
||||
user: { login: string }
|
||||
content: string
|
||||
created_at: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createIssueReactionTool: ToolConfig<
|
||||
CreateIssueReactionParams,
|
||||
CreateIssueReactionResponse
|
||||
> = {
|
||||
id: 'github_create_issue_reaction',
|
||||
name: 'GitHub Create Issue Reaction',
|
||||
description: 'Add a reaction to an issue',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
issue_number: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue number',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Reaction type: +1 (thumbs up), -1 (thumbs down), laugh, confused, heart, hooray, rocket, eyes',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/issues/${params.issue_number}/reactions`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.squirrel-girl-preview+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => ({
|
||||
content: params.content,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const content = `Added ${data.content} reaction to issue by ${data.user?.login ?? 'unknown'}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
user: { login: data.user?.login ?? 'unknown' },
|
||||
content: data.content,
|
||||
created_at: data.created_at,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Reaction metadata',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Reaction ID' },
|
||||
user: { type: 'object', description: 'User who reacted' },
|
||||
content: { type: 'string', description: 'Reaction type' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const createIssueReactionV2Tool: ToolConfig<CreateIssueReactionParams, any> = {
|
||||
id: 'github_create_issue_reaction_v2',
|
||||
name: createIssueReactionTool.name,
|
||||
description: createIssueReactionTool.description,
|
||||
version: '2.0.0',
|
||||
params: createIssueReactionTool.params,
|
||||
request: createIssueReactionTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: data,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'number', description: 'Reaction ID' },
|
||||
user: { type: 'object', description: 'User who reacted' },
|
||||
content: { type: 'string', description: 'Reaction type' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
},
|
||||
}
|
||||
182
apps/sim/tools/github/create_milestone.ts
Normal file
182
apps/sim/tools/github/create_milestone.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface CreateMilestoneParams {
|
||||
owner: string
|
||||
repo: string
|
||||
title: string
|
||||
state?: 'open' | 'closed'
|
||||
description?: string
|
||||
due_on?: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface CreateMilestoneResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
number: number
|
||||
title: string
|
||||
description: string | null
|
||||
state: string
|
||||
html_url: string
|
||||
due_on: string | null
|
||||
open_issues: number
|
||||
closed_issues: number
|
||||
created_at: string
|
||||
creator: { login: string }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const createMilestoneTool: ToolConfig<CreateMilestoneParams, CreateMilestoneResponse> = {
|
||||
id: 'github_create_milestone',
|
||||
name: 'GitHub Create Milestone',
|
||||
description: 'Create a milestone in a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone title',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'State: open or closed (default: open)',
|
||||
default: 'open',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone description',
|
||||
},
|
||||
due_on: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Due date (ISO 8601 format, e.g., 2024-12-31T23:59:59Z)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/repos/${params.owner}/${params.repo}/milestones`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => ({
|
||||
title: params.title,
|
||||
state: params.state ?? 'open',
|
||||
description: params.description,
|
||||
due_on: params.due_on,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const content = `Created milestone: ${data.title}
|
||||
Number: ${data.number}
|
||||
State: ${data.state}
|
||||
Due: ${data.due_on ?? 'No due date'}
|
||||
${data.html_url}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
number: data.number,
|
||||
title: data.title,
|
||||
description: data.description ?? null,
|
||||
state: data.state,
|
||||
html_url: data.html_url,
|
||||
due_on: data.due_on ?? null,
|
||||
open_issues: data.open_issues,
|
||||
closed_issues: data.closed_issues,
|
||||
created_at: data.created_at,
|
||||
creator: { login: data.creator?.login ?? 'unknown' },
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Milestone metadata',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues count' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues count' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
creator: { type: 'object', description: 'Creator info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const createMilestoneV2Tool: ToolConfig<CreateMilestoneParams, any> = {
|
||||
id: 'github_create_milestone_v2',
|
||||
name: createMilestoneTool.name,
|
||||
description: createMilestoneTool.description,
|
||||
version: '2.0.0',
|
||||
params: createMilestoneTool.params,
|
||||
request: createMilestoneTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
due_on: data.due_on ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
creator: { type: 'object', description: 'Creator' },
|
||||
},
|
||||
}
|
||||
128
apps/sim/tools/github/delete_comment_reaction.ts
Normal file
128
apps/sim/tools/github/delete_comment_reaction.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface DeleteCommentReactionParams {
|
||||
owner: string
|
||||
repo: string
|
||||
comment_id: number
|
||||
reaction_id: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface DeleteCommentReactionResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
deleted: boolean
|
||||
reaction_id: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteCommentReactionTool: ToolConfig<
|
||||
DeleteCommentReactionParams,
|
||||
DeleteCommentReactionResponse
|
||||
> = {
|
||||
id: 'github_delete_comment_reaction',
|
||||
name: 'GitHub Delete Comment Reaction',
|
||||
description: 'Remove a reaction from an issue comment',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
comment_id: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment ID',
|
||||
},
|
||||
reaction_id: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Reaction ID to delete',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/issues/comments/${params.comment_id}/reactions/${params.reaction_id}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.squirrel-girl-preview+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const deleted = response.status === 204
|
||||
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
content: deleted
|
||||
? `Successfully deleted reaction ${params?.reaction_id}`
|
||||
: `Failed to delete reaction ${params?.reaction_id}`,
|
||||
metadata: {
|
||||
deleted,
|
||||
reaction_id: params?.reaction_id ?? 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Delete operation metadata',
|
||||
properties: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
reaction_id: { type: 'number', description: 'The deleted reaction ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const deleteCommentReactionV2Tool: ToolConfig<DeleteCommentReactionParams, any> = {
|
||||
id: 'github_delete_comment_reaction_v2',
|
||||
name: deleteCommentReactionTool.name,
|
||||
description: deleteCommentReactionTool.description,
|
||||
version: '2.0.0',
|
||||
params: deleteCommentReactionTool.params,
|
||||
request: deleteCommentReactionTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const deleted = response.status === 204
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
deleted,
|
||||
reaction_id: params?.reaction_id ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
reaction_id: { type: 'number', description: 'The deleted reaction ID' },
|
||||
},
|
||||
}
|
||||
103
apps/sim/tools/github/delete_gist.ts
Normal file
103
apps/sim/tools/github/delete_gist.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface DeleteGistParams {
|
||||
gist_id: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface DeleteGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
deleted: boolean
|
||||
gist_id: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteGistTool: ToolConfig<DeleteGistParams, DeleteGistResponse> = {
|
||||
id: 'github_delete_gist',
|
||||
name: 'GitHub Delete Gist',
|
||||
description: 'Delete a gist by ID',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID to delete',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const deleted = response.status === 204
|
||||
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
content: deleted
|
||||
? `Successfully deleted gist ${params?.gist_id}`
|
||||
: `Failed to delete gist ${params?.gist_id}`,
|
||||
metadata: {
|
||||
deleted,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Delete operation metadata',
|
||||
properties: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
gist_id: { type: 'string', description: 'The deleted gist ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const deleteGistV2Tool: ToolConfig<DeleteGistParams, any> = {
|
||||
id: 'github_delete_gist_v2',
|
||||
name: deleteGistTool.name,
|
||||
description: deleteGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: deleteGistTool.params,
|
||||
request: deleteGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const deleted = response.status === 204
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
deleted,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
gist_id: { type: 'string', description: 'The deleted gist ID' },
|
||||
},
|
||||
}
|
||||
128
apps/sim/tools/github/delete_issue_reaction.ts
Normal file
128
apps/sim/tools/github/delete_issue_reaction.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface DeleteIssueReactionParams {
|
||||
owner: string
|
||||
repo: string
|
||||
issue_number: number
|
||||
reaction_id: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface DeleteIssueReactionResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
deleted: boolean
|
||||
reaction_id: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteIssueReactionTool: ToolConfig<
|
||||
DeleteIssueReactionParams,
|
||||
DeleteIssueReactionResponse
|
||||
> = {
|
||||
id: 'github_delete_issue_reaction',
|
||||
name: 'GitHub Delete Issue Reaction',
|
||||
description: 'Remove a reaction from an issue',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
issue_number: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue number',
|
||||
},
|
||||
reaction_id: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Reaction ID to delete',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/issues/${params.issue_number}/reactions/${params.reaction_id}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.squirrel-girl-preview+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const deleted = response.status === 204
|
||||
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
content: deleted
|
||||
? `Successfully deleted reaction ${params?.reaction_id}`
|
||||
: `Failed to delete reaction ${params?.reaction_id}`,
|
||||
metadata: {
|
||||
deleted,
|
||||
reaction_id: params?.reaction_id ?? 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Delete operation metadata',
|
||||
properties: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
reaction_id: { type: 'number', description: 'The deleted reaction ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const deleteIssueReactionV2Tool: ToolConfig<DeleteIssueReactionParams, any> = {
|
||||
id: 'github_delete_issue_reaction_v2',
|
||||
name: deleteIssueReactionTool.name,
|
||||
description: deleteIssueReactionTool.description,
|
||||
version: '2.0.0',
|
||||
params: deleteIssueReactionTool.params,
|
||||
request: deleteIssueReactionTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const deleted = response.status === 204
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
deleted,
|
||||
reaction_id: params?.reaction_id ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
reaction_id: { type: 'number', description: 'The deleted reaction ID' },
|
||||
},
|
||||
}
|
||||
118
apps/sim/tools/github/delete_milestone.ts
Normal file
118
apps/sim/tools/github/delete_milestone.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface DeleteMilestoneParams {
|
||||
owner: string
|
||||
repo: string
|
||||
milestone_number: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface DeleteMilestoneResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
deleted: boolean
|
||||
milestone_number: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteMilestoneTool: ToolConfig<DeleteMilestoneParams, DeleteMilestoneResponse> = {
|
||||
id: 'github_delete_milestone',
|
||||
name: 'GitHub Delete Milestone',
|
||||
description: 'Delete a milestone from a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
milestone_number: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone number to delete',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/milestones/${params.milestone_number}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const deleted = response.status === 204
|
||||
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
content: deleted
|
||||
? `Successfully deleted milestone #${params?.milestone_number}`
|
||||
: `Failed to delete milestone #${params?.milestone_number}`,
|
||||
metadata: {
|
||||
deleted,
|
||||
milestone_number: params?.milestone_number ?? 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Delete operation metadata',
|
||||
properties: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
milestone_number: { type: 'number', description: 'The deleted milestone number' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const deleteMilestoneV2Tool: ToolConfig<DeleteMilestoneParams, any> = {
|
||||
id: 'github_delete_milestone_v2',
|
||||
name: deleteMilestoneTool.name,
|
||||
description: deleteMilestoneTool.description,
|
||||
version: '2.0.0',
|
||||
params: deleteMilestoneTool.params,
|
||||
request: deleteMilestoneTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const deleted = response.status === 204
|
||||
return {
|
||||
success: deleted,
|
||||
output: {
|
||||
deleted,
|
||||
milestone_number: params?.milestone_number ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||
milestone_number: { type: 'number', description: 'The deleted milestone number' },
|
||||
},
|
||||
}
|
||||
131
apps/sim/tools/github/fork_gist.ts
Normal file
131
apps/sim/tools/github/fork_gist.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ForkGistParams {
|
||||
gist_id: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ForkGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: string
|
||||
html_url: string
|
||||
git_pull_url: string
|
||||
description: string | null
|
||||
public: boolean
|
||||
created_at: string
|
||||
owner: { login: string }
|
||||
files: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const forkGistTool: ToolConfig<ForkGistParams, ForkGistResponse> = {
|
||||
id: 'github_fork_gist',
|
||||
name: 'GitHub Fork Gist',
|
||||
description: 'Fork a gist to create your own copy',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID to fork',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}/forks`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const files = Object.keys(data.files ?? {})
|
||||
|
||||
const content = `Forked gist: ${data.html_url}
|
||||
Description: ${data.description ?? 'No description'}
|
||||
Files: ${files.join(', ')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
html_url: data.html_url,
|
||||
git_pull_url: data.git_pull_url,
|
||||
description: data.description ?? null,
|
||||
public: data.public,
|
||||
created_at: data.created_at,
|
||||
owner: { login: data.owner?.login ?? 'unknown' },
|
||||
files,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Forked gist metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'New gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
git_pull_url: { type: 'string', description: 'Git pull URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
files: { type: 'array', description: 'File names' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const forkGistV2Tool: ToolConfig<ForkGistParams, any> = {
|
||||
id: 'github_fork_gist_v2',
|
||||
name: forkGistTool.name,
|
||||
description: forkGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: forkGistTool.params,
|
||||
request: forkGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
files: data.files ?? {},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'New gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
files: { type: 'object', description: 'Files' },
|
||||
},
|
||||
}
|
||||
179
apps/sim/tools/github/fork_repo.ts
Normal file
179
apps/sim/tools/github/fork_repo.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ForkRepoParams {
|
||||
owner: string
|
||||
repo: string
|
||||
organization?: string
|
||||
name?: string
|
||||
default_branch_only?: boolean
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ForkRepoResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: number
|
||||
full_name: string
|
||||
html_url: string
|
||||
clone_url: string
|
||||
ssh_url: string
|
||||
default_branch: string
|
||||
fork: boolean
|
||||
parent: { full_name: string; html_url: string }
|
||||
owner: { login: string }
|
||||
created_at: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const forkRepoTool: ToolConfig<ForkRepoParams, ForkRepoResponse> = {
|
||||
id: 'github_fork_repo',
|
||||
name: 'GitHub Fork Repository',
|
||||
description: 'Fork a repository to your account or an organization',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner to fork from',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name to fork',
|
||||
},
|
||||
organization: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization to fork into (omit to fork to your account)',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom name for the forked repository',
|
||||
},
|
||||
default_branch_only: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Only fork the default branch (default: false)',
|
||||
default: false,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/repos/${params.owner}/${params.repo}/forks`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {}
|
||||
if (params.organization) body.organization = params.organization
|
||||
if (params.name) body.name = params.name
|
||||
if (params.default_branch_only !== undefined)
|
||||
body.default_branch_only = params.default_branch_only
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const content = `Forked repository: ${data.html_url}
|
||||
Forked from: ${data.parent?.full_name ?? 'unknown'}
|
||||
Clone URL: ${data.clone_url}
|
||||
Default branch: ${data.default_branch}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
full_name: data.full_name,
|
||||
html_url: data.html_url,
|
||||
clone_url: data.clone_url,
|
||||
ssh_url: data.ssh_url,
|
||||
default_branch: data.default_branch,
|
||||
fork: data.fork,
|
||||
parent: {
|
||||
full_name: data.parent?.full_name ?? '',
|
||||
html_url: data.parent?.html_url ?? '',
|
||||
},
|
||||
owner: { login: data.owner?.login ?? 'unknown' },
|
||||
created_at: data.created_at,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Forked repository metadata',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name (owner/repo)' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
clone_url: { type: 'string', description: 'HTTPS clone URL' },
|
||||
ssh_url: { type: 'string', description: 'SSH clone URL' },
|
||||
default_branch: { type: 'string', description: 'Default branch' },
|
||||
fork: { type: 'boolean', description: 'Is a fork' },
|
||||
parent: { type: 'object', description: 'Parent repository' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const forkRepoV2Tool: ToolConfig<ForkRepoParams, any> = {
|
||||
id: 'github_fork_repo_v2',
|
||||
name: forkRepoTool.name,
|
||||
description: forkRepoTool.description,
|
||||
version: '2.0.0',
|
||||
params: forkRepoTool.params,
|
||||
request: forkRepoTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
parent: data.parent ?? null,
|
||||
source: data.source ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
clone_url: { type: 'string', description: 'Clone URL' },
|
||||
ssh_url: { type: 'string', description: 'SSH URL' },
|
||||
default_branch: { type: 'string', description: 'Default branch' },
|
||||
fork: { type: 'boolean', description: 'Is a fork' },
|
||||
parent: { type: 'object', description: 'Parent repository', optional: true },
|
||||
owner: { type: 'object', description: 'Owner' },
|
||||
},
|
||||
}
|
||||
202
apps/sim/tools/github/get_commit.ts
Normal file
202
apps/sim/tools/github/get_commit.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GetCommitParams {
|
||||
owner: string
|
||||
repo: string
|
||||
ref: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface GetCommitResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
sha: string
|
||||
html_url: string
|
||||
message: string
|
||||
author: { name: string; email: string; date: string; login?: string }
|
||||
committer: { name: string; email: string; date: string; login?: string }
|
||||
stats: { additions: number; deletions: number; total: number }
|
||||
files: Array<{
|
||||
filename: string
|
||||
status: string
|
||||
additions: number
|
||||
deletions: number
|
||||
changes: number
|
||||
patch?: string
|
||||
}>
|
||||
parents: Array<{ sha: string; html_url: string }>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getCommitTool: ToolConfig<GetCommitParams, GetCommitResponse> = {
|
||||
id: 'github_get_commit',
|
||||
name: 'GitHub Get Commit',
|
||||
description: 'Get detailed information about a specific commit including files changed and stats',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
ref: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Commit SHA, branch name, or tag name',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/commits/${params.ref}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const files = (data.files ?? []).map((f: any) => ({
|
||||
filename: f.filename,
|
||||
status: f.status,
|
||||
additions: f.additions,
|
||||
deletions: f.deletions,
|
||||
changes: f.changes,
|
||||
patch: f.patch,
|
||||
}))
|
||||
|
||||
const metadata = {
|
||||
sha: data.sha,
|
||||
html_url: data.html_url,
|
||||
message: data.commit.message,
|
||||
author: {
|
||||
name: data.commit.author.name,
|
||||
email: data.commit.author.email,
|
||||
date: data.commit.author.date,
|
||||
login: data.author?.login,
|
||||
},
|
||||
committer: {
|
||||
name: data.commit.committer.name,
|
||||
email: data.commit.committer.email,
|
||||
date: data.commit.committer.date,
|
||||
login: data.committer?.login,
|
||||
},
|
||||
stats: data.stats ?? { additions: 0, deletions: 0, total: 0 },
|
||||
files,
|
||||
parents: data.parents.map((p: any) => ({ sha: p.sha, html_url: p.html_url })),
|
||||
}
|
||||
|
||||
const content = `Commit ${data.sha.substring(0, 7)}
|
||||
Message: ${data.commit.message.split('\n')[0]}
|
||||
Author: ${metadata.author.login ?? metadata.author.name} (${metadata.author.date})
|
||||
Stats: +${metadata.stats.additions} -${metadata.stats.deletions} (${files.length} files)
|
||||
${data.html_url}
|
||||
|
||||
Files changed:
|
||||
${files.map((f: any) => ` ${f.status}: ${f.filename} (+${f.additions} -${f.deletions})`).join('\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable commit details' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Commit metadata',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Full commit SHA' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
message: { type: 'string', description: 'Commit message' },
|
||||
author: { type: 'object', description: 'Author info' },
|
||||
committer: { type: 'object', description: 'Committer info' },
|
||||
stats: {
|
||||
type: 'object',
|
||||
description: 'Change stats',
|
||||
properties: {
|
||||
additions: { type: 'number', description: 'Lines added' },
|
||||
deletions: { type: 'number', description: 'Lines deleted' },
|
||||
total: { type: 'number', description: 'Total changes' },
|
||||
},
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
description: 'Changed files',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
filename: { type: 'string', description: 'File path' },
|
||||
status: { type: 'string', description: 'Change type' },
|
||||
additions: { type: 'number', description: 'Lines added' },
|
||||
deletions: { type: 'number', description: 'Lines deleted' },
|
||||
changes: { type: 'number', description: 'Total changes' },
|
||||
patch: { type: 'string', description: 'Diff patch', optional: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
parents: { type: 'array', description: 'Parent commits' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const getCommitV2Tool: ToolConfig<GetCommitParams, any> = {
|
||||
id: 'github_get_commit_v2',
|
||||
name: getCommitTool.name,
|
||||
description: getCommitTool.description,
|
||||
version: '2.0.0',
|
||||
params: getCommitTool.params,
|
||||
request: getCommitTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
author: data.author ?? null,
|
||||
committer: data.committer ?? null,
|
||||
stats: data.stats ?? null,
|
||||
files: data.files ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
commit: { type: 'object', description: 'Commit data' },
|
||||
author: { type: 'object', description: 'GitHub user', optional: true },
|
||||
committer: { type: 'object', description: 'GitHub user', optional: true },
|
||||
stats: { type: 'object', description: 'Change stats', optional: true },
|
||||
files: { type: 'array', description: 'Changed files' },
|
||||
parents: { type: 'array', description: 'Parent commits' },
|
||||
},
|
||||
}
|
||||
177
apps/sim/tools/github/get_gist.ts
Normal file
177
apps/sim/tools/github/get_gist.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GetGistParams {
|
||||
gist_id: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface GetGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: string
|
||||
html_url: string
|
||||
git_pull_url: string
|
||||
git_push_url: string
|
||||
description: string | null
|
||||
public: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number; content: string }
|
||||
>
|
||||
owner: { login: string }
|
||||
comments: number
|
||||
forks_url: string
|
||||
commits_url: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getGistTool: ToolConfig<GetGistParams, GetGistResponse> = {
|
||||
id: 'github_get_gist',
|
||||
name: 'GitHub Get Gist',
|
||||
description: 'Get a gist by ID including its file contents',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number; content: string }
|
||||
> = {}
|
||||
for (const [key, value] of Object.entries(data.files ?? {})) {
|
||||
const file = value as any
|
||||
files[key] = {
|
||||
filename: file.filename,
|
||||
type: file.type,
|
||||
language: file.language ?? null,
|
||||
size: file.size,
|
||||
content: file.content ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
id: data.id,
|
||||
html_url: data.html_url,
|
||||
git_pull_url: data.git_pull_url,
|
||||
git_push_url: data.git_push_url,
|
||||
description: data.description ?? null,
|
||||
public: data.public,
|
||||
created_at: data.created_at,
|
||||
updated_at: data.updated_at,
|
||||
files,
|
||||
owner: { login: data.owner?.login ?? 'unknown' },
|
||||
comments: data.comments ?? 0,
|
||||
forks_url: data.forks_url,
|
||||
commits_url: data.commits_url,
|
||||
}
|
||||
|
||||
const fileList = Object.entries(files)
|
||||
.map(([name, f]) => `${name} (${f.language ?? 'unknown'}, ${f.size} bytes)`)
|
||||
.join(', ')
|
||||
|
||||
const content = `Gist: ${data.html_url}
|
||||
Description: ${data.description ?? 'No description'}
|
||||
Public: ${data.public} | Comments: ${data.comments ?? 0}
|
||||
Owner: ${data.owner?.login ?? 'unknown'}
|
||||
Files: ${fileList}
|
||||
|
||||
${Object.entries(files)
|
||||
.map(([name, f]) => `--- ${name} ---\n${f.content}`)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable gist with file contents' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Gist metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
git_pull_url: { type: 'string', description: 'Git pull URL' },
|
||||
git_push_url: { type: 'string', description: 'Git push URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Files with content' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
comments: { type: 'number', description: 'Comment count' },
|
||||
forks_url: { type: 'string', description: 'Forks URL' },
|
||||
commits_url: { type: 'string', description: 'Commits URL' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const getGistV2Tool: ToolConfig<GetGistParams, any> = {
|
||||
id: 'github_get_gist_v2',
|
||||
name: getGistTool.name,
|
||||
description: getGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: getGistTool.params,
|
||||
request: getGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
files: data.files ?? {},
|
||||
comments: data.comments ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Files with content' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
comments: { type: 'number', description: 'Comment count' },
|
||||
},
|
||||
}
|
||||
167
apps/sim/tools/github/get_milestone.ts
Normal file
167
apps/sim/tools/github/get_milestone.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GetMilestoneParams {
|
||||
owner: string
|
||||
repo: string
|
||||
milestone_number: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface GetMilestoneResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
number: number
|
||||
title: string
|
||||
description: string | null
|
||||
state: string
|
||||
html_url: string
|
||||
due_on: string | null
|
||||
open_issues: number
|
||||
closed_issues: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
closed_at: string | null
|
||||
creator: { login: string }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getMilestoneTool: ToolConfig<GetMilestoneParams, GetMilestoneResponse> = {
|
||||
id: 'github_get_milestone',
|
||||
name: 'GitHub Get Milestone',
|
||||
description: 'Get a specific milestone by number',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
milestone_number: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone number',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/milestones/${params.milestone_number}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const progress =
|
||||
data.open_issues + data.closed_issues > 0
|
||||
? Math.round((data.closed_issues / (data.open_issues + data.closed_issues)) * 100)
|
||||
: 0
|
||||
|
||||
const content = `Milestone: ${data.title} (#${data.number})
|
||||
State: ${data.state} | Progress: ${progress}% (${data.closed_issues}/${data.open_issues + data.closed_issues} issues)
|
||||
Due: ${data.due_on ?? 'No due date'}
|
||||
Description: ${data.description ?? 'No description'}
|
||||
${data.html_url}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
number: data.number,
|
||||
title: data.title,
|
||||
description: data.description ?? null,
|
||||
state: data.state,
|
||||
html_url: data.html_url,
|
||||
due_on: data.due_on ?? null,
|
||||
open_issues: data.open_issues,
|
||||
closed_issues: data.closed_issues,
|
||||
created_at: data.created_at,
|
||||
updated_at: data.updated_at,
|
||||
closed_at: data.closed_at ?? null,
|
||||
creator: { login: data.creator?.login ?? 'unknown' },
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable milestone details' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Milestone metadata',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues count' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues count' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
closed_at: { type: 'string', description: 'Close date', optional: true },
|
||||
creator: { type: 'object', description: 'Creator info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const getMilestoneV2Tool: ToolConfig<GetMilestoneParams, any> = {
|
||||
id: 'github_get_milestone_v2',
|
||||
name: getMilestoneTool.name,
|
||||
description: getMilestoneTool.description,
|
||||
version: '2.0.0',
|
||||
params: getMilestoneTool.params,
|
||||
request: getMilestoneTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
due_on: data.due_on ?? null,
|
||||
closed_at: data.closed_at ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
closed_at: { type: 'string', description: 'Close date', optional: true },
|
||||
creator: { type: 'object', description: 'Creator' },
|
||||
},
|
||||
}
|
||||
@@ -1,27 +1,54 @@
|
||||
import { addAssigneesTool, addAssigneesV2Tool } from '@/tools/github/add_assignees'
|
||||
import { addLabelsTool, addLabelsV2Tool } from '@/tools/github/add_labels'
|
||||
import { cancelWorkflowRunTool, cancelWorkflowRunV2Tool } from '@/tools/github/cancel_workflow_run'
|
||||
import { checkStarTool, checkStarV2Tool } from '@/tools/github/check_star'
|
||||
import { closeIssueTool, closeIssueV2Tool } from '@/tools/github/close_issue'
|
||||
import { closePRTool, closePRV2Tool } from '@/tools/github/close_pr'
|
||||
import { commentTool, commentV2Tool } from '@/tools/github/comment'
|
||||
import { compareCommitsTool, compareCommitsV2Tool } from '@/tools/github/compare_commits'
|
||||
import { createBranchTool, createBranchV2Tool } from '@/tools/github/create_branch'
|
||||
import {
|
||||
createCommentReactionTool,
|
||||
createCommentReactionV2Tool,
|
||||
} from '@/tools/github/create_comment_reaction'
|
||||
import { createFileTool, createFileV2Tool } from '@/tools/github/create_file'
|
||||
import { createGistTool, createGistV2Tool } from '@/tools/github/create_gist'
|
||||
import { createIssueTool, createIssueV2Tool } from '@/tools/github/create_issue'
|
||||
import {
|
||||
createIssueReactionTool,
|
||||
createIssueReactionV2Tool,
|
||||
} from '@/tools/github/create_issue_reaction'
|
||||
import { createMilestoneTool, createMilestoneV2Tool } from '@/tools/github/create_milestone'
|
||||
import { createPRTool, createPRV2Tool } from '@/tools/github/create_pr'
|
||||
import { createProjectTool, createProjectV2Tool } from '@/tools/github/create_project'
|
||||
import { createReleaseTool, createReleaseV2Tool } from '@/tools/github/create_release'
|
||||
import { deleteBranchTool, deleteBranchV2Tool } from '@/tools/github/delete_branch'
|
||||
import { deleteCommentTool, deleteCommentV2Tool } from '@/tools/github/delete_comment'
|
||||
import {
|
||||
deleteCommentReactionTool,
|
||||
deleteCommentReactionV2Tool,
|
||||
} from '@/tools/github/delete_comment_reaction'
|
||||
import { deleteFileTool, deleteFileV2Tool } from '@/tools/github/delete_file'
|
||||
import { deleteGistTool, deleteGistV2Tool } from '@/tools/github/delete_gist'
|
||||
import {
|
||||
deleteIssueReactionTool,
|
||||
deleteIssueReactionV2Tool,
|
||||
} from '@/tools/github/delete_issue_reaction'
|
||||
import { deleteMilestoneTool, deleteMilestoneV2Tool } from '@/tools/github/delete_milestone'
|
||||
import { deleteProjectTool, deleteProjectV2Tool } from '@/tools/github/delete_project'
|
||||
import { deleteReleaseTool, deleteReleaseV2Tool } from '@/tools/github/delete_release'
|
||||
import { forkGistTool, forkGistV2Tool } from '@/tools/github/fork_gist'
|
||||
import { forkRepoTool, forkRepoV2Tool } from '@/tools/github/fork_repo'
|
||||
import { getBranchTool, getBranchV2Tool } from '@/tools/github/get_branch'
|
||||
import {
|
||||
getBranchProtectionTool,
|
||||
getBranchProtectionV2Tool,
|
||||
} from '@/tools/github/get_branch_protection'
|
||||
import { getCommitTool, getCommitV2Tool } from '@/tools/github/get_commit'
|
||||
import { getFileContentTool, getFileContentV2Tool } from '@/tools/github/get_file_content'
|
||||
import { getGistTool, getGistV2Tool } from '@/tools/github/get_gist'
|
||||
import { getIssueTool, getIssueV2Tool } from '@/tools/github/get_issue'
|
||||
import { getMilestoneTool, getMilestoneV2Tool } from '@/tools/github/get_milestone'
|
||||
import { getPRFilesTool, getPRFilesV2Tool } from '@/tools/github/get_pr_files'
|
||||
import { getProjectTool, getProjectV2Tool } from '@/tools/github/get_project'
|
||||
import { getReleaseTool, getReleaseV2Tool } from '@/tools/github/get_release'
|
||||
@@ -31,12 +58,17 @@ import { getWorkflowRunTool, getWorkflowRunV2Tool } from '@/tools/github/get_wor
|
||||
import { issueCommentTool, issueCommentV2Tool } from '@/tools/github/issue_comment'
|
||||
import { latestCommitTool, latestCommitV2Tool } from '@/tools/github/latest_commit'
|
||||
import { listBranchesTool, listBranchesV2Tool } from '@/tools/github/list_branches'
|
||||
import { listCommitsTool, listCommitsV2Tool } from '@/tools/github/list_commits'
|
||||
import { listForksTool, listForksV2Tool } from '@/tools/github/list_forks'
|
||||
import { listGistsTool, listGistsV2Tool } from '@/tools/github/list_gists'
|
||||
import { listIssueCommentsTool, listIssueCommentsV2Tool } from '@/tools/github/list_issue_comments'
|
||||
import { listIssuesTool, listIssuesV2Tool } from '@/tools/github/list_issues'
|
||||
import { listMilestonesTool, listMilestonesV2Tool } from '@/tools/github/list_milestones'
|
||||
import { listPRCommentsTool, listPRCommentsV2Tool } from '@/tools/github/list_pr_comments'
|
||||
import { listProjectsTool, listProjectsV2Tool } from '@/tools/github/list_projects'
|
||||
import { listPRsTool, listPRsV2Tool } from '@/tools/github/list_prs'
|
||||
import { listReleasesTool, listReleasesV2Tool } from '@/tools/github/list_releases'
|
||||
import { listStargazersTool, listStargazersV2Tool } from '@/tools/github/list_stargazers'
|
||||
import { listWorkflowRunsTool, listWorkflowRunsV2Tool } from '@/tools/github/list_workflow_runs'
|
||||
import { listWorkflowsTool, listWorkflowsV2Tool } from '@/tools/github/list_workflows'
|
||||
import { mergePRTool, mergePRV2Tool } from '@/tools/github/merge_pr'
|
||||
@@ -45,20 +77,38 @@ import { removeLabelTool, removeLabelV2Tool } from '@/tools/github/remove_label'
|
||||
import { repoInfoTool, repoInfoV2Tool } from '@/tools/github/repo_info'
|
||||
import { requestReviewersTool, requestReviewersV2Tool } from '@/tools/github/request_reviewers'
|
||||
import { rerunWorkflowTool, rerunWorkflowV2Tool } from '@/tools/github/rerun_workflow'
|
||||
import { searchCodeTool, searchCodeV2Tool } from '@/tools/github/search_code'
|
||||
import { searchCommitsTool, searchCommitsV2Tool } from '@/tools/github/search_commits'
|
||||
import { searchIssuesTool, searchIssuesV2Tool } from '@/tools/github/search_issues'
|
||||
import { searchReposTool, searchReposV2Tool } from '@/tools/github/search_repos'
|
||||
import { searchUsersTool, searchUsersV2Tool } from '@/tools/github/search_users'
|
||||
import { starGistTool, starGistV2Tool } from '@/tools/github/star_gist'
|
||||
import { starRepoTool, starRepoV2Tool } from '@/tools/github/star_repo'
|
||||
import { triggerWorkflowTool, triggerWorkflowV2Tool } from '@/tools/github/trigger_workflow'
|
||||
import { unstarGistTool, unstarGistV2Tool } from '@/tools/github/unstar_gist'
|
||||
import { unstarRepoTool, unstarRepoV2Tool } from '@/tools/github/unstar_repo'
|
||||
import {
|
||||
updateBranchProtectionTool,
|
||||
updateBranchProtectionV2Tool,
|
||||
} from '@/tools/github/update_branch_protection'
|
||||
import { updateCommentTool, updateCommentV2Tool } from '@/tools/github/update_comment'
|
||||
import { updateFileTool, updateFileV2Tool } from '@/tools/github/update_file'
|
||||
import { updateGistTool, updateGistV2Tool } from '@/tools/github/update_gist'
|
||||
import { updateIssueTool, updateIssueV2Tool } from '@/tools/github/update_issue'
|
||||
import { updateMilestoneTool, updateMilestoneV2Tool } from '@/tools/github/update_milestone'
|
||||
import { updatePRTool, updatePRV2Tool } from '@/tools/github/update_pr'
|
||||
import { updateProjectTool, updateProjectV2Tool } from '@/tools/github/update_project'
|
||||
import { updateReleaseTool, updateReleaseV2Tool } from '@/tools/github/update_release'
|
||||
|
||||
// Existing exports
|
||||
export const githubAddAssigneesTool = addAssigneesTool
|
||||
export const githubAddAssigneesV2Tool = addAssigneesV2Tool
|
||||
export const githubAddLabelsTool = addLabelsTool
|
||||
export const githubAddLabelsV2Tool = addLabelsV2Tool
|
||||
export const githubCancelWorkflowRunTool = cancelWorkflowRunTool
|
||||
export const githubCancelWorkflowRunV2Tool = cancelWorkflowRunV2Tool
|
||||
export const githubCloseIssueTool = closeIssueTool
|
||||
export const githubCloseIssueV2Tool = closeIssueV2Tool
|
||||
export const githubClosePRTool = closePRTool
|
||||
export const githubClosePRV2Tool = closePRV2Tool
|
||||
export const githubCommentTool = commentTool
|
||||
@@ -67,6 +117,8 @@ export const githubCreateBranchTool = createBranchTool
|
||||
export const githubCreateBranchV2Tool = createBranchV2Tool
|
||||
export const githubCreateFileTool = createFileTool
|
||||
export const githubCreateFileV2Tool = createFileV2Tool
|
||||
export const githubCreateIssueTool = createIssueTool
|
||||
export const githubCreateIssueV2Tool = createIssueV2Tool
|
||||
export const githubCreatePRTool = createPRTool
|
||||
export const githubCreatePRV2Tool = createPRV2Tool
|
||||
export const githubCreateProjectTool = createProjectTool
|
||||
@@ -89,6 +141,8 @@ export const githubGetBranchProtectionTool = getBranchProtectionTool
|
||||
export const githubGetBranchProtectionV2Tool = getBranchProtectionV2Tool
|
||||
export const githubGetFileContentTool = getFileContentTool
|
||||
export const githubGetFileContentV2Tool = getFileContentV2Tool
|
||||
export const githubGetIssueTool = getIssueTool
|
||||
export const githubGetIssueV2Tool = getIssueV2Tool
|
||||
export const githubGetPRFilesTool = getPRFilesTool
|
||||
export const githubGetPRFilesV2Tool = getPRFilesV2Tool
|
||||
export const githubGetProjectTool = getProjectTool
|
||||
@@ -109,6 +163,8 @@ export const githubListBranchesTool = listBranchesTool
|
||||
export const githubListBranchesV2Tool = listBranchesV2Tool
|
||||
export const githubListIssueCommentsTool = listIssueCommentsTool
|
||||
export const githubListIssueCommentsV2Tool = listIssueCommentsV2Tool
|
||||
export const githubListIssuesTool = listIssuesTool
|
||||
export const githubListIssuesV2Tool = listIssuesV2Tool
|
||||
export const githubListPRCommentsTool = listPRCommentsTool
|
||||
export const githubListPRCommentsV2Tool = listPRCommentsV2Tool
|
||||
export const githubListPRsTool = listPRsTool
|
||||
@@ -125,6 +181,8 @@ export const githubMergePRTool = mergePRTool
|
||||
export const githubMergePRV2Tool = mergePRV2Tool
|
||||
export const githubPrTool = prTool
|
||||
export const githubPrV2Tool = prV2Tool
|
||||
export const githubRemoveLabelTool = removeLabelTool
|
||||
export const githubRemoveLabelV2Tool = removeLabelV2Tool
|
||||
export const githubRepoInfoTool = repoInfoTool
|
||||
export const githubRepoInfoV2Tool = repoInfoV2Tool
|
||||
export const githubRequestReviewersTool = requestReviewersTool
|
||||
@@ -139,25 +197,87 @@ export const githubUpdateCommentTool = updateCommentTool
|
||||
export const githubUpdateCommentV2Tool = updateCommentV2Tool
|
||||
export const githubUpdateFileTool = updateFileTool
|
||||
export const githubUpdateFileV2Tool = updateFileV2Tool
|
||||
export const githubUpdateIssueTool = updateIssueTool
|
||||
export const githubUpdateIssueV2Tool = updateIssueV2Tool
|
||||
export const githubUpdatePRTool = updatePRTool
|
||||
export const githubUpdatePRV2Tool = updatePRV2Tool
|
||||
export const githubUpdateProjectTool = updateProjectTool
|
||||
export const githubUpdateProjectV2Tool = updateProjectV2Tool
|
||||
export const githubUpdateReleaseTool = updateReleaseTool
|
||||
export const githubUpdateReleaseV2Tool = updateReleaseV2Tool
|
||||
export const githubAddAssigneesTool = addAssigneesTool
|
||||
export const githubAddAssigneesV2Tool = addAssigneesV2Tool
|
||||
export const githubAddLabelsTool = addLabelsTool
|
||||
export const githubAddLabelsV2Tool = addLabelsV2Tool
|
||||
export const githubCloseIssueTool = closeIssueTool
|
||||
export const githubCloseIssueV2Tool = closeIssueV2Tool
|
||||
export const githubCreateIssueTool = createIssueTool
|
||||
export const githubCreateIssueV2Tool = createIssueV2Tool
|
||||
export const githubGetIssueTool = getIssueTool
|
||||
export const githubGetIssueV2Tool = getIssueV2Tool
|
||||
export const githubListIssuesTool = listIssuesTool
|
||||
export const githubListIssuesV2Tool = listIssuesV2Tool
|
||||
export const githubRemoveLabelTool = removeLabelTool
|
||||
export const githubRemoveLabelV2Tool = removeLabelV2Tool
|
||||
export const githubUpdateIssueTool = updateIssueTool
|
||||
export const githubUpdateIssueV2Tool = updateIssueV2Tool
|
||||
|
||||
// New exports - Search tools
|
||||
export const githubSearchCodeTool = searchCodeTool
|
||||
export const githubSearchCodeV2Tool = searchCodeV2Tool
|
||||
export const githubSearchCommitsTool = searchCommitsTool
|
||||
export const githubSearchCommitsV2Tool = searchCommitsV2Tool
|
||||
export const githubSearchIssuesTool = searchIssuesTool
|
||||
export const githubSearchIssuesV2Tool = searchIssuesV2Tool
|
||||
export const githubSearchReposTool = searchReposTool
|
||||
export const githubSearchReposV2Tool = searchReposV2Tool
|
||||
export const githubSearchUsersTool = searchUsersTool
|
||||
export const githubSearchUsersV2Tool = searchUsersV2Tool
|
||||
|
||||
// New exports - Commit tools
|
||||
export const githubListCommitsTool = listCommitsTool
|
||||
export const githubListCommitsV2Tool = listCommitsV2Tool
|
||||
export const githubGetCommitTool = getCommitTool
|
||||
export const githubGetCommitV2Tool = getCommitV2Tool
|
||||
export const githubCompareCommitsTool = compareCommitsTool
|
||||
export const githubCompareCommitsV2Tool = compareCommitsV2Tool
|
||||
|
||||
// New exports - Gist tools
|
||||
export const githubCreateGistTool = createGistTool
|
||||
export const githubCreateGistV2Tool = createGistV2Tool
|
||||
export const githubGetGistTool = getGistTool
|
||||
export const githubGetGistV2Tool = getGistV2Tool
|
||||
export const githubListGistsTool = listGistsTool
|
||||
export const githubListGistsV2Tool = listGistsV2Tool
|
||||
export const githubUpdateGistTool = updateGistTool
|
||||
export const githubUpdateGistV2Tool = updateGistV2Tool
|
||||
export const githubDeleteGistTool = deleteGistTool
|
||||
export const githubDeleteGistV2Tool = deleteGistV2Tool
|
||||
export const githubForkGistTool = forkGistTool
|
||||
export const githubForkGistV2Tool = forkGistV2Tool
|
||||
export const githubStarGistTool = starGistTool
|
||||
export const githubStarGistV2Tool = starGistV2Tool
|
||||
export const githubUnstarGistTool = unstarGistTool
|
||||
export const githubUnstarGistV2Tool = unstarGistV2Tool
|
||||
|
||||
// New exports - Fork tools
|
||||
export const githubForkRepoTool = forkRepoTool
|
||||
export const githubForkRepoV2Tool = forkRepoV2Tool
|
||||
export const githubListForksTool = listForksTool
|
||||
export const githubListForksV2Tool = listForksV2Tool
|
||||
|
||||
// New exports - Milestone tools
|
||||
export const githubCreateMilestoneTool = createMilestoneTool
|
||||
export const githubCreateMilestoneV2Tool = createMilestoneV2Tool
|
||||
export const githubGetMilestoneTool = getMilestoneTool
|
||||
export const githubGetMilestoneV2Tool = getMilestoneV2Tool
|
||||
export const githubListMilestonesTool = listMilestonesTool
|
||||
export const githubListMilestonesV2Tool = listMilestonesV2Tool
|
||||
export const githubUpdateMilestoneTool = updateMilestoneTool
|
||||
export const githubUpdateMilestoneV2Tool = updateMilestoneV2Tool
|
||||
export const githubDeleteMilestoneTool = deleteMilestoneTool
|
||||
export const githubDeleteMilestoneV2Tool = deleteMilestoneV2Tool
|
||||
|
||||
// New exports - Reaction tools
|
||||
export const githubCreateIssueReactionTool = createIssueReactionTool
|
||||
export const githubCreateIssueReactionV2Tool = createIssueReactionV2Tool
|
||||
export const githubDeleteIssueReactionTool = deleteIssueReactionTool
|
||||
export const githubDeleteIssueReactionV2Tool = deleteIssueReactionV2Tool
|
||||
export const githubCreateCommentReactionTool = createCommentReactionTool
|
||||
export const githubCreateCommentReactionV2Tool = createCommentReactionV2Tool
|
||||
export const githubDeleteCommentReactionTool = deleteCommentReactionTool
|
||||
export const githubDeleteCommentReactionV2Tool = deleteCommentReactionV2Tool
|
||||
|
||||
// New exports - Star tools
|
||||
export const githubStarRepoTool = starRepoTool
|
||||
export const githubStarRepoV2Tool = starRepoV2Tool
|
||||
export const githubUnstarRepoTool = unstarRepoTool
|
||||
export const githubUnstarRepoV2Tool = unstarRepoV2Tool
|
||||
export const githubCheckStarTool = checkStarTool
|
||||
export const githubCheckStarV2Tool = checkStarV2Tool
|
||||
export const githubListStargazersTool = listStargazersTool
|
||||
export const githubListStargazersV2Tool = listStargazersV2Tool
|
||||
|
||||
243
apps/sim/tools/github/list_commits.ts
Normal file
243
apps/sim/tools/github/list_commits.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ListCommitsParams {
|
||||
owner: string
|
||||
repo: string
|
||||
sha?: string
|
||||
path?: string
|
||||
author?: string
|
||||
committer?: string
|
||||
since?: string
|
||||
until?: string
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ListCommitsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
commits: Array<{
|
||||
sha: string
|
||||
html_url: string
|
||||
message: string
|
||||
author: { name: string; email: string; date: string; login?: string }
|
||||
committer: { name: string; email: string; date: string; login?: string }
|
||||
}>
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listCommitsTool: ToolConfig<ListCommitsParams, ListCommitsResponse> = {
|
||||
id: 'github_list_commits',
|
||||
name: 'GitHub List Commits',
|
||||
description:
|
||||
'List commits in a repository with optional filtering by SHA, path, author, committer, or date range',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
sha: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'SHA or branch to start listing commits from',
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Only commits containing this file path',
|
||||
},
|
||||
author: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'GitHub login or email address to filter by author',
|
||||
},
|
||||
committer: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'GitHub login or email address to filter by committer',
|
||||
},
|
||||
since: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Only commits after this date (ISO 8601 format)',
|
||||
},
|
||||
until: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Only commits before this date (ISO 8601 format)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://api.github.com/repos/${params.owner}/${params.repo}/commits`)
|
||||
if (params.sha) url.searchParams.append('sha', params.sha)
|
||||
if (params.path) url.searchParams.append('path', params.path)
|
||||
if (params.author) url.searchParams.append('author', params.author)
|
||||
if (params.committer) url.searchParams.append('committer', params.committer)
|
||||
if (params.since) url.searchParams.append('since', params.since)
|
||||
if (params.until) url.searchParams.append('until', params.until)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const commits = data.map((item: any) => ({
|
||||
sha: item.sha,
|
||||
html_url: item.html_url,
|
||||
message: item.commit.message,
|
||||
author: {
|
||||
name: item.commit.author.name,
|
||||
email: item.commit.author.email,
|
||||
date: item.commit.author.date,
|
||||
login: item.author?.login,
|
||||
},
|
||||
committer: {
|
||||
name: item.commit.committer.name,
|
||||
email: item.commit.committer.email,
|
||||
date: item.commit.committer.date,
|
||||
login: item.committer?.login,
|
||||
},
|
||||
}))
|
||||
|
||||
const content = `Found ${commits.length} commit(s):
|
||||
${commits
|
||||
.map(
|
||||
(c: any) =>
|
||||
`${c.sha.substring(0, 7)} - ${c.message.split('\n')[0]}
|
||||
Author: ${c.author.login ?? c.author.name} (${c.author.date})
|
||||
${c.html_url}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
commits,
|
||||
count: commits.length,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable commit list' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Commits metadata',
|
||||
properties: {
|
||||
commits: {
|
||||
type: 'array',
|
||||
description: 'Array of commits',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
message: { type: 'string', description: 'Commit message' },
|
||||
author: { type: 'object', description: 'Author info' },
|
||||
committer: { type: 'object', description: 'Committer info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of commits returned' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const listCommitsV2Tool: ToolConfig<ListCommitsParams, any> = {
|
||||
id: 'github_list_commits_v2',
|
||||
name: listCommitsTool.name,
|
||||
description: listCommitsTool.description,
|
||||
version: '2.0.0',
|
||||
params: listCommitsTool.params,
|
||||
request: listCommitsTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items: data.map((item: any) => ({
|
||||
...item,
|
||||
author: item.author ?? null,
|
||||
committer: item.committer ?? null,
|
||||
})),
|
||||
count: data.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of commit objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
commit: { type: 'object', description: 'Commit data' },
|
||||
author: { type: 'object', description: 'GitHub user', optional: true },
|
||||
committer: { type: 'object', description: 'GitHub user', optional: true },
|
||||
parents: { type: 'array', description: 'Parent commits' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of commits returned' },
|
||||
},
|
||||
}
|
||||
201
apps/sim/tools/github/list_forks.ts
Normal file
201
apps/sim/tools/github/list_forks.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ListForksParams {
|
||||
owner: string
|
||||
repo: string
|
||||
sort?: 'newest' | 'oldest' | 'stargazers' | 'watchers'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ListForksResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
forks: Array<{
|
||||
id: number
|
||||
full_name: string
|
||||
html_url: string
|
||||
owner: { login: string }
|
||||
stargazers_count: number
|
||||
forks_count: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
default_branch: string
|
||||
}>
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listForksTool: ToolConfig<ListForksParams, ListForksResponse> = {
|
||||
id: 'github_list_forks',
|
||||
name: 'GitHub List Forks',
|
||||
description: 'List forks of a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by: newest, oldest, stargazers, watchers (default: newest)',
|
||||
default: 'newest',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://api.github.com/repos/${params.owner}/${params.repo}/forks`)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const forks = data.map((f: any) => ({
|
||||
id: f.id,
|
||||
full_name: f.full_name,
|
||||
html_url: f.html_url,
|
||||
owner: { login: f.owner?.login ?? 'unknown' },
|
||||
stargazers_count: f.stargazers_count,
|
||||
forks_count: f.forks_count,
|
||||
created_at: f.created_at,
|
||||
updated_at: f.updated_at,
|
||||
default_branch: f.default_branch,
|
||||
}))
|
||||
|
||||
const content = `Found ${forks.length} fork(s):
|
||||
${forks
|
||||
.map(
|
||||
(f: any) =>
|
||||
`${f.full_name} ⭐ ${f.stargazers_count}
|
||||
Owner: ${f.owner.login}
|
||||
${f.html_url}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
forks,
|
||||
count: forks.length,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable fork list' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Forks metadata',
|
||||
properties: {
|
||||
forks: {
|
||||
type: 'array',
|
||||
description: 'Array of forks',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
stargazers_count: { type: 'number', description: 'Star count' },
|
||||
forks_count: { type: 'number', description: 'Fork count' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
default_branch: { type: 'string', description: 'Default branch' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of forks returned' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const listForksV2Tool: ToolConfig<ListForksParams, any> = {
|
||||
id: 'github_list_forks_v2',
|
||||
name: listForksTool.name,
|
||||
description: listForksTool.description,
|
||||
version: '2.0.0',
|
||||
params: listForksTool.params,
|
||||
request: listForksTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items: data,
|
||||
count: data.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of fork repository objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
owner: { type: 'object', description: 'Owner' },
|
||||
stargazers_count: { type: 'number', description: 'Stars' },
|
||||
forks_count: { type: 'number', description: 'Forks' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of forks returned' },
|
||||
},
|
||||
}
|
||||
201
apps/sim/tools/github/list_gists.ts
Normal file
201
apps/sim/tools/github/list_gists.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ListGistsParams {
|
||||
username?: string
|
||||
since?: string
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ListGistsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
gists: Array<{
|
||||
id: string
|
||||
html_url: string
|
||||
description: string | null
|
||||
public: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
files: string[]
|
||||
owner: { login: string }
|
||||
comments: number
|
||||
}>
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listGistsTool: ToolConfig<ListGistsParams, ListGistsResponse> = {
|
||||
id: 'github_list_gists',
|
||||
name: 'GitHub List Gists',
|
||||
description: 'List gists for a user or the authenticated user',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
username: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: "GitHub username (omit for authenticated user's gists)",
|
||||
},
|
||||
since: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Only gists updated after this time (ISO 8601)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const baseUrl = params.username
|
||||
? `https://api.github.com/users/${params.username}/gists`
|
||||
: 'https://api.github.com/gists'
|
||||
const url = new URL(baseUrl)
|
||||
if (params.since) url.searchParams.append('since', params.since)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const gists = data.map((g: any) => ({
|
||||
id: g.id,
|
||||
html_url: g.html_url,
|
||||
description: g.description ?? null,
|
||||
public: g.public,
|
||||
created_at: g.created_at,
|
||||
updated_at: g.updated_at,
|
||||
files: Object.keys(g.files ?? {}),
|
||||
owner: { login: g.owner?.login ?? 'unknown' },
|
||||
comments: g.comments ?? 0,
|
||||
}))
|
||||
|
||||
const content = `Found ${gists.length} gist(s):
|
||||
${gists
|
||||
.map(
|
||||
(g: any) =>
|
||||
`${g.id} - ${g.description ?? 'No description'} (${g.public ? 'public' : 'secret'})
|
||||
Files: ${g.files.join(', ')}
|
||||
${g.html_url}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
gists,
|
||||
count: gists.length,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable gist list' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Gists metadata',
|
||||
properties: {
|
||||
gists: {
|
||||
type: 'array',
|
||||
description: 'Array of gists',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'array', description: 'File names' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
comments: { type: 'number', description: 'Comment count' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of gists returned' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const listGistsV2Tool: ToolConfig<ListGistsParams, any> = {
|
||||
id: 'github_list_gists_v2',
|
||||
name: listGistsTool.name,
|
||||
description: listGistsTool.description,
|
||||
version: '2.0.0',
|
||||
params: listGistsTool.params,
|
||||
request: listGistsTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items: data.map((g: any) => ({
|
||||
...g,
|
||||
description: g.description ?? null,
|
||||
files: g.files ?? {},
|
||||
comments: g.comments ?? 0,
|
||||
})),
|
||||
count: data.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of gist objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
files: { type: 'object', description: 'Files' },
|
||||
owner: { type: 'object', description: 'Owner' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of gists returned' },
|
||||
},
|
||||
}
|
||||
226
apps/sim/tools/github/list_milestones.ts
Normal file
226
apps/sim/tools/github/list_milestones.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ListMilestonesParams {
|
||||
owner: string
|
||||
repo: string
|
||||
state?: 'open' | 'closed' | 'all'
|
||||
sort?: 'due_on' | 'completeness'
|
||||
direction?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ListMilestonesResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
milestones: Array<{
|
||||
number: number
|
||||
title: string
|
||||
description: string | null
|
||||
state: string
|
||||
html_url: string
|
||||
due_on: string | null
|
||||
open_issues: number
|
||||
closed_issues: number
|
||||
}>
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listMilestonesTool: ToolConfig<ListMilestonesParams, ListMilestonesResponse> = {
|
||||
id: 'github_list_milestones',
|
||||
name: 'GitHub List Milestones',
|
||||
description: 'List milestones in a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by state: open, closed, all (default: open)',
|
||||
default: 'open',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by: due_on or completeness (default: due_on)',
|
||||
default: 'due_on',
|
||||
},
|
||||
direction: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction: asc or desc (default: asc)',
|
||||
default: 'asc',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://api.github.com/repos/${params.owner}/${params.repo}/milestones`)
|
||||
if (params.state) url.searchParams.append('state', params.state)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.direction) url.searchParams.append('direction', params.direction)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const milestones = data.map((m: any) => {
|
||||
const total = m.open_issues + m.closed_issues
|
||||
const progress = total > 0 ? Math.round((m.closed_issues / total) * 100) : 0
|
||||
return {
|
||||
number: m.number,
|
||||
title: m.title,
|
||||
description: m.description ?? null,
|
||||
state: m.state,
|
||||
html_url: m.html_url,
|
||||
due_on: m.due_on ?? null,
|
||||
open_issues: m.open_issues,
|
||||
closed_issues: m.closed_issues,
|
||||
progress,
|
||||
}
|
||||
})
|
||||
|
||||
const content = `Found ${milestones.length} milestone(s):
|
||||
${milestones
|
||||
.map(
|
||||
(m: any) =>
|
||||
`#${m.number}: ${m.title} (${m.state})
|
||||
Progress: ${m.progress}% (${m.closed_issues}/${m.open_issues + m.closed_issues} issues)
|
||||
Due: ${m.due_on ?? 'No due date'}
|
||||
${m.html_url}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
milestones,
|
||||
count: milestones.length,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable milestone list' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Milestones metadata',
|
||||
properties: {
|
||||
milestones: {
|
||||
type: 'array',
|
||||
description: 'Array of milestones',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of milestones returned' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const listMilestonesV2Tool: ToolConfig<ListMilestonesParams, any> = {
|
||||
id: 'github_list_milestones_v2',
|
||||
name: listMilestonesTool.name,
|
||||
description: listMilestonesTool.description,
|
||||
version: '2.0.0',
|
||||
params: listMilestonesTool.params,
|
||||
request: listMilestonesTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items: data.map((m: any) => ({
|
||||
...m,
|
||||
description: m.description ?? null,
|
||||
due_on: m.due_on ?? null,
|
||||
})),
|
||||
count: data.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of milestone objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of milestones returned' },
|
||||
},
|
||||
}
|
||||
172
apps/sim/tools/github/list_stargazers.ts
Normal file
172
apps/sim/tools/github/list_stargazers.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface ListStargazersParams {
|
||||
owner: string
|
||||
repo: string
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface ListStargazersResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
stargazers: Array<{
|
||||
login: string
|
||||
id: number
|
||||
avatar_url: string
|
||||
html_url: string
|
||||
type: string
|
||||
}>
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listStargazersTool: ToolConfig<ListStargazersParams, ListStargazersResponse> = {
|
||||
id: 'github_list_stargazers',
|
||||
name: 'GitHub List Stargazers',
|
||||
description: 'List users who have starred a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://api.github.com/repos/${params.owner}/${params.repo}/stargazers`)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const stargazers = data.map((u: any) => ({
|
||||
login: u.login,
|
||||
id: u.id,
|
||||
avatar_url: u.avatar_url,
|
||||
html_url: u.html_url,
|
||||
type: u.type,
|
||||
}))
|
||||
|
||||
const content = `Found ${stargazers.length} stargazer(s):
|
||||
${stargazers.map((u: any) => `@${u.login} (${u.type}) - ${u.html_url}`).join('\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
stargazers,
|
||||
count: stargazers.length,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable stargazer list' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Stargazers metadata',
|
||||
properties: {
|
||||
stargazers: {
|
||||
type: 'array',
|
||||
description: 'Array of stargazers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
login: { type: 'string', description: 'Username' },
|
||||
id: { type: 'number', description: 'User ID' },
|
||||
avatar_url: { type: 'string', description: 'Avatar URL' },
|
||||
html_url: { type: 'string', description: 'Profile URL' },
|
||||
type: { type: 'string', description: 'User or Organization' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of stargazers returned' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const listStargazersV2Tool: ToolConfig<ListStargazersParams, any> = {
|
||||
id: 'github_list_stargazers_v2',
|
||||
name: listStargazersTool.name,
|
||||
description: listStargazersTool.description,
|
||||
version: '2.0.0',
|
||||
params: listStargazersTool.params,
|
||||
request: listStargazersTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
items: data,
|
||||
count: data.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of user objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
login: { type: 'string', description: 'Username' },
|
||||
id: { type: 'number', description: 'User ID' },
|
||||
avatar_url: { type: 'string', description: 'Avatar URL' },
|
||||
html_url: { type: 'string', description: 'Profile URL' },
|
||||
type: { type: 'string', description: 'User or Organization' },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of stargazers returned' },
|
||||
},
|
||||
}
|
||||
211
apps/sim/tools/github/search_code.ts
Normal file
211
apps/sim/tools/github/search_code.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface SearchCodeParams {
|
||||
q: string
|
||||
sort?: 'indexed'
|
||||
order?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface SearchCodeResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
total_count: number
|
||||
incomplete_results: boolean
|
||||
items: Array<{
|
||||
name: string
|
||||
path: string
|
||||
sha: string
|
||||
html_url: string
|
||||
repository: {
|
||||
full_name: string
|
||||
html_url: string
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const searchCodeTool: ToolConfig<SearchCodeParams, SearchCodeResponse> = {
|
||||
id: 'github_search_code',
|
||||
name: 'GitHub Search Code',
|
||||
description:
|
||||
'Search for code across GitHub repositories. Use qualifiers like repo:owner/name, language:js, path:src, extension:py',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
q: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Search query with optional qualifiers (repo:, language:, path:, extension:, user:, org:)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by indexed date (default: best match)',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort order: asc or desc (default: desc)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.github.com/search/code')
|
||||
url.searchParams.append('q', params.q)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.order) url.searchParams.append('order', params.order)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const items = data.items.map((item: any) => ({
|
||||
name: item.name,
|
||||
path: item.path,
|
||||
sha: item.sha,
|
||||
html_url: item.html_url,
|
||||
repository: {
|
||||
full_name: item.repository.full_name,
|
||||
html_url: item.repository.html_url,
|
||||
},
|
||||
}))
|
||||
|
||||
const content = `Found ${data.total_count} code result(s)${data.incomplete_results ? ' (incomplete)' : ''}:
|
||||
${items
|
||||
.map(
|
||||
(item: any) =>
|
||||
`- ${item.repository.full_name}/${item.path}
|
||||
${item.html_url}`
|
||||
)
|
||||
.join('\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable search results' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Search results metadata',
|
||||
properties: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of code matches',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'File name' },
|
||||
path: { type: 'string', description: 'File path' },
|
||||
sha: { type: 'string', description: 'Blob SHA' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
repository: {
|
||||
type: 'object',
|
||||
description: 'Repository info',
|
||||
properties: {
|
||||
full_name: { type: 'string', description: 'Repository full name' },
|
||||
html_url: { type: 'string', description: 'Repository URL' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const searchCodeV2Tool: ToolConfig<SearchCodeParams, any> = {
|
||||
id: 'github_search_code_v2',
|
||||
name: searchCodeTool.name,
|
||||
description: searchCodeTool.description,
|
||||
version: '2.0.0',
|
||||
params: searchCodeTool.params,
|
||||
request: searchCodeTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items: data.items.map((item: any) => ({
|
||||
...item,
|
||||
text_matches: item.text_matches ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of code matches from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'File name' },
|
||||
path: { type: 'string', description: 'File path' },
|
||||
sha: { type: 'string', description: 'Blob SHA' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
repository: { type: 'object', description: 'Repository object' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
224
apps/sim/tools/github/search_commits.ts
Normal file
224
apps/sim/tools/github/search_commits.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface SearchCommitsParams {
|
||||
q: string
|
||||
sort?: 'author-date' | 'committer-date'
|
||||
order?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface SearchCommitsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
total_count: number
|
||||
incomplete_results: boolean
|
||||
items: Array<{
|
||||
sha: string
|
||||
html_url: string
|
||||
commit: {
|
||||
message: string
|
||||
author: { name: string; email: string; date: string }
|
||||
committer: { name: string; email: string; date: string }
|
||||
}
|
||||
author: { login: string } | null
|
||||
committer: { login: string } | null
|
||||
repository: { full_name: string; html_url: string }
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const searchCommitsTool: ToolConfig<SearchCommitsParams, SearchCommitsResponse> = {
|
||||
id: 'github_search_commits',
|
||||
name: 'GitHub Search Commits',
|
||||
description:
|
||||
'Search for commits across GitHub. Use qualifiers like repo:owner/name, author:user, committer:user, author-date:>2023-01-01',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
q: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Search query with optional qualifiers (repo:, author:, committer:, author-date:, committer-date:, merge:true/false)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by: author-date or committer-date (default: best match)',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort order: asc or desc (default: desc)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.github.com/search/commits')
|
||||
url.searchParams.append('q', params.q)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.order) url.searchParams.append('order', params.order)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.cloak-preview+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const items = data.items.map((item: any) => ({
|
||||
sha: item.sha,
|
||||
html_url: item.html_url,
|
||||
commit: {
|
||||
message: item.commit.message,
|
||||
author: item.commit.author,
|
||||
committer: item.commit.committer,
|
||||
},
|
||||
author: item.author ? { login: item.author.login } : null,
|
||||
committer: item.committer ? { login: item.committer.login } : null,
|
||||
repository: {
|
||||
full_name: item.repository.full_name,
|
||||
html_url: item.repository.html_url,
|
||||
},
|
||||
}))
|
||||
|
||||
const content = `Found ${data.total_count} commit(s)${data.incomplete_results ? ' (incomplete)' : ''}:
|
||||
${items
|
||||
.map(
|
||||
(item: any) =>
|
||||
`${item.sha.substring(0, 7)} - ${item.commit.message.split('\n')[0]}
|
||||
Repository: ${item.repository.full_name}
|
||||
Author: ${item.author?.login ?? item.commit.author.name} (${item.commit.author.date})
|
||||
${item.html_url}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable search results' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Search results metadata',
|
||||
properties: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of commits',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
commit: {
|
||||
type: 'object',
|
||||
description: 'Commit details',
|
||||
properties: {
|
||||
message: { type: 'string', description: 'Commit message' },
|
||||
author: { type: 'object', description: 'Author info' },
|
||||
committer: { type: 'object', description: 'Committer info' },
|
||||
},
|
||||
},
|
||||
author: { type: 'object', description: 'GitHub user (author)', optional: true },
|
||||
committer: { type: 'object', description: 'GitHub user (committer)', optional: true },
|
||||
repository: { type: 'object', description: 'Repository info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const searchCommitsV2Tool: ToolConfig<SearchCommitsParams, any> = {
|
||||
id: 'github_search_commits_v2',
|
||||
name: searchCommitsTool.name,
|
||||
description: searchCommitsTool.description,
|
||||
version: '2.0.0',
|
||||
params: searchCommitsTool.params,
|
||||
request: searchCommitsTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items: data.items.map((item: any) => ({
|
||||
...item,
|
||||
author: item.author ?? null,
|
||||
committer: item.committer ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of commit objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
sha: { type: 'string', description: 'Commit SHA' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
commit: { type: 'object', description: 'Commit data' },
|
||||
author: { type: 'object', description: 'GitHub user', optional: true },
|
||||
committer: { type: 'object', description: 'GitHub user', optional: true },
|
||||
repository: { type: 'object', description: 'Repository' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
240
apps/sim/tools/github/search_issues.ts
Normal file
240
apps/sim/tools/github/search_issues.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface SearchIssuesParams {
|
||||
q: string
|
||||
sort?:
|
||||
| 'comments'
|
||||
| 'reactions'
|
||||
| 'reactions-+1'
|
||||
| 'reactions--1'
|
||||
| 'reactions-smile'
|
||||
| 'reactions-thinking_face'
|
||||
| 'reactions-heart'
|
||||
| 'reactions-tada'
|
||||
| 'interactions'
|
||||
| 'created'
|
||||
| 'updated'
|
||||
order?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface SearchIssuesResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
total_count: number
|
||||
incomplete_results: boolean
|
||||
items: Array<{
|
||||
number: number
|
||||
title: string
|
||||
state: string
|
||||
html_url: string
|
||||
user: { login: string }
|
||||
labels: string[]
|
||||
created_at: string
|
||||
updated_at: string
|
||||
comments: number
|
||||
is_pull_request: boolean
|
||||
repository_url: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const searchIssuesTool: ToolConfig<SearchIssuesParams, SearchIssuesResponse> = {
|
||||
id: 'github_search_issues',
|
||||
name: 'GitHub Search Issues',
|
||||
description:
|
||||
'Search for issues and pull requests across GitHub. Use qualifiers like repo:owner/name, is:issue, is:pr, state:open, label:bug, author:user',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
q: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Search query with optional qualifiers (repo:, is:issue, is:pr, state:, label:, author:, assignee:)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Sort by: comments, reactions, created, updated, interactions (default: best match)',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort order: asc or desc (default: desc)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.github.com/search/issues')
|
||||
url.searchParams.append('q', params.q)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.order) url.searchParams.append('order', params.order)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const items = data.items.map((item: any) => ({
|
||||
number: item.number,
|
||||
title: item.title,
|
||||
state: item.state,
|
||||
html_url: item.html_url,
|
||||
user: { login: item.user?.login ?? 'unknown' },
|
||||
labels: item.labels?.map((l: any) => l.name) ?? [],
|
||||
created_at: item.created_at,
|
||||
updated_at: item.updated_at,
|
||||
comments: item.comments ?? 0,
|
||||
is_pull_request: !!item.pull_request,
|
||||
repository_url: item.repository_url,
|
||||
}))
|
||||
|
||||
const content = `Found ${data.total_count} result(s)${data.incomplete_results ? ' (incomplete)' : ''}:
|
||||
${items
|
||||
.map(
|
||||
(item: any) =>
|
||||
`#${item.number}: "${item.title}" (${item.state}) [${item.is_pull_request ? 'PR' : 'Issue'}]
|
||||
${item.html_url}
|
||||
Labels: ${item.labels.length > 0 ? item.labels.join(', ') : 'none'} | Comments: ${item.comments}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable search results' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Search results metadata',
|
||||
properties: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of issues/PRs',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Issue/PR number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
state: { type: 'string', description: 'State (open/closed)' },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
user: { type: 'object', description: 'Author info' },
|
||||
labels: { type: 'array', description: 'Label names' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Last update date' },
|
||||
comments: { type: 'number', description: 'Comment count' },
|
||||
is_pull_request: { type: 'boolean', description: 'Whether this is a PR' },
|
||||
repository_url: { type: 'string', description: 'Repository API URL' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const searchIssuesV2Tool: ToolConfig<SearchIssuesParams, any> = {
|
||||
id: 'github_search_issues_v2',
|
||||
name: searchIssuesTool.name,
|
||||
description: searchIssuesTool.description,
|
||||
version: '2.0.0',
|
||||
params: searchIssuesTool.params,
|
||||
request: searchIssuesTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items: data.items.map((item: any) => ({
|
||||
...item,
|
||||
body: item.body ?? null,
|
||||
closed_at: item.closed_at ?? null,
|
||||
milestone: item.milestone ?? null,
|
||||
labels: item.labels ?? [],
|
||||
assignees: item.assignees ?? [],
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of issue/PR objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Issue ID' },
|
||||
number: { type: 'number', description: 'Issue number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
body: { type: 'string', description: 'Body text', optional: true },
|
||||
user: { type: 'object', description: 'Author' },
|
||||
labels: { type: 'array', description: 'Labels' },
|
||||
assignees: { type: 'array', description: 'Assignees' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
closed_at: { type: 'string', description: 'Close date', optional: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
226
apps/sim/tools/github/search_repos.ts
Normal file
226
apps/sim/tools/github/search_repos.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface SearchReposParams {
|
||||
q: string
|
||||
sort?: 'stars' | 'forks' | 'help-wanted-issues' | 'updated'
|
||||
order?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface SearchReposResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
total_count: number
|
||||
incomplete_results: boolean
|
||||
items: Array<{
|
||||
id: number
|
||||
full_name: string
|
||||
description: string | null
|
||||
html_url: string
|
||||
stargazers_count: number
|
||||
forks_count: number
|
||||
language: string | null
|
||||
topics: string[]
|
||||
created_at: string
|
||||
updated_at: string
|
||||
owner: { login: string }
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const searchReposTool: ToolConfig<SearchReposParams, SearchReposResponse> = {
|
||||
id: 'github_search_repos',
|
||||
name: 'GitHub Search Repositories',
|
||||
description:
|
||||
'Search for repositories across GitHub. Use qualifiers like language:python, stars:>1000, topic:react, user:owner, org:name',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
q: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Search query with optional qualifiers (language:, stars:, forks:, topic:, user:, org:, in:name,description,readme)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by: stars, forks, help-wanted-issues, updated (default: best match)',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort order: asc or desc (default: desc)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.github.com/search/repositories')
|
||||
url.searchParams.append('q', params.q)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.order) url.searchParams.append('order', params.order)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const items = data.items.map((item: any) => ({
|
||||
id: item.id,
|
||||
full_name: item.full_name,
|
||||
description: item.description ?? null,
|
||||
html_url: item.html_url,
|
||||
stargazers_count: item.stargazers_count,
|
||||
forks_count: item.forks_count,
|
||||
language: item.language ?? null,
|
||||
topics: item.topics ?? [],
|
||||
created_at: item.created_at,
|
||||
updated_at: item.updated_at,
|
||||
owner: { login: item.owner?.login ?? 'unknown' },
|
||||
}))
|
||||
|
||||
const content = `Found ${data.total_count} repository(s)${data.incomplete_results ? ' (incomplete)' : ''}:
|
||||
${items
|
||||
.map(
|
||||
(item: any) =>
|
||||
`${item.full_name} ⭐ ${item.stargazers_count} | 🍴 ${item.forks_count}
|
||||
${item.description ?? 'No description'}
|
||||
${item.html_url}
|
||||
Language: ${item.language ?? 'N/A'} | Topics: ${item.topics.length > 0 ? item.topics.join(', ') : 'none'}`
|
||||
)
|
||||
.join('\n\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable search results' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Search results metadata',
|
||||
properties: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of repositories',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name (owner/repo)' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
html_url: { type: 'string', description: 'GitHub web URL' },
|
||||
stargazers_count: { type: 'number', description: 'Star count' },
|
||||
forks_count: { type: 'number', description: 'Fork count' },
|
||||
language: { type: 'string', description: 'Primary language', optional: true },
|
||||
topics: { type: 'array', description: 'Repository topics' },
|
||||
created_at: { type: 'string', description: 'Creation date' },
|
||||
updated_at: { type: 'string', description: 'Last update date' },
|
||||
owner: { type: 'object', description: 'Owner info' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const searchReposV2Tool: ToolConfig<SearchReposParams, any> = {
|
||||
id: 'github_search_repos_v2',
|
||||
name: searchReposTool.name,
|
||||
description: searchReposTool.description,
|
||||
version: '2.0.0',
|
||||
params: searchReposTool.params,
|
||||
request: searchReposTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items: data.items.map((item: any) => ({
|
||||
...item,
|
||||
description: item.description ?? null,
|
||||
language: item.language ?? null,
|
||||
topics: item.topics ?? [],
|
||||
license: item.license ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of repository objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Repository ID' },
|
||||
full_name: { type: 'string', description: 'Full name' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
stargazers_count: { type: 'number', description: 'Stars' },
|
||||
forks_count: { type: 'number', description: 'Forks' },
|
||||
open_issues_count: { type: 'number', description: 'Open issues' },
|
||||
language: { type: 'string', description: 'Language', optional: true },
|
||||
topics: { type: 'array', description: 'Topics' },
|
||||
owner: { type: 'object', description: 'Owner' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
193
apps/sim/tools/github/search_users.ts
Normal file
193
apps/sim/tools/github/search_users.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface SearchUsersParams {
|
||||
q: string
|
||||
sort?: 'followers' | 'repositories' | 'joined'
|
||||
order?: 'asc' | 'desc'
|
||||
per_page?: number
|
||||
page?: number
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface SearchUsersResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
total_count: number
|
||||
incomplete_results: boolean
|
||||
items: Array<{
|
||||
id: number
|
||||
login: string
|
||||
html_url: string
|
||||
avatar_url: string
|
||||
type: string
|
||||
score: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const searchUsersTool: ToolConfig<SearchUsersParams, SearchUsersResponse> = {
|
||||
id: 'github_search_users',
|
||||
name: 'GitHub Search Users',
|
||||
description:
|
||||
'Search for users and organizations on GitHub. Use qualifiers like type:user, type:org, followers:>1000, repos:>10, location:city',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
q: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Search query with optional qualifiers (type:user/org, followers:, repos:, location:, language:, created:)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort by: followers, repositories, joined (default: best match)',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort order: asc or desc (default: desc)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (max 100, default: 30)',
|
||||
default: 30,
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (default: 1)',
|
||||
default: 1,
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL('https://api.github.com/search/users')
|
||||
url.searchParams.append('q', params.q)
|
||||
if (params.sort) url.searchParams.append('sort', params.sort)
|
||||
if (params.order) url.searchParams.append('order', params.order)
|
||||
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
|
||||
if (params.page) url.searchParams.append('page', String(params.page))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const items = data.items.map((item: any) => ({
|
||||
id: item.id,
|
||||
login: item.login,
|
||||
html_url: item.html_url,
|
||||
avatar_url: item.avatar_url,
|
||||
type: item.type,
|
||||
score: item.score,
|
||||
}))
|
||||
|
||||
const content = `Found ${data.total_count} user(s)/organization(s)${data.incomplete_results ? ' (incomplete)' : ''}:
|
||||
${items.map((item: any) => `@${item.login} (${item.type}) - ${item.html_url}`).join('\n')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable search results' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Search results metadata',
|
||||
properties: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of users/orgs',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'User ID' },
|
||||
login: { type: 'string', description: 'Username' },
|
||||
html_url: { type: 'string', description: 'Profile URL' },
|
||||
avatar_url: { type: 'string', description: 'Avatar URL' },
|
||||
type: { type: 'string', description: 'User or Organization' },
|
||||
score: { type: 'number', description: 'Search relevance score' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const searchUsersV2Tool: ToolConfig<SearchUsersParams, any> = {
|
||||
id: 'github_search_users_v2',
|
||||
name: searchUsersTool.name,
|
||||
description: searchUsersTool.description,
|
||||
version: '2.0.0',
|
||||
params: searchUsersTool.params,
|
||||
request: searchUsersTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
total_count: data.total_count,
|
||||
incomplete_results: data.incomplete_results,
|
||||
items: data.items,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
total_count: { type: 'number', description: 'Total matching results' },
|
||||
incomplete_results: { type: 'boolean', description: 'Whether results are incomplete' },
|
||||
items: {
|
||||
type: 'array',
|
||||
description: 'Array of user objects from GitHub API',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'User ID' },
|
||||
login: { type: 'string', description: 'Username' },
|
||||
html_url: { type: 'string', description: 'Profile URL' },
|
||||
avatar_url: { type: 'string', description: 'Avatar URL' },
|
||||
type: { type: 'string', description: 'User or Organization' },
|
||||
site_admin: { type: 'boolean', description: 'Is site admin' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
104
apps/sim/tools/github/star_gist.ts
Normal file
104
apps/sim/tools/github/star_gist.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface StarGistParams {
|
||||
gist_id: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface StarGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
starred: boolean
|
||||
gist_id: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const starGistTool: ToolConfig<StarGistParams, StarGistResponse> = {
|
||||
id: 'github_star_gist',
|
||||
name: 'GitHub Star Gist',
|
||||
description: 'Star a gist',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID to star',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}/star`,
|
||||
method: 'PUT',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Length': '0',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const starred = response.status === 204
|
||||
|
||||
return {
|
||||
success: starred,
|
||||
output: {
|
||||
content: starred
|
||||
? `Successfully starred gist ${params?.gist_id}`
|
||||
: `Failed to star gist ${params?.gist_id}`,
|
||||
metadata: {
|
||||
starred,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Star operation metadata',
|
||||
properties: {
|
||||
starred: { type: 'boolean', description: 'Whether starring succeeded' },
|
||||
gist_id: { type: 'string', description: 'The gist ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const starGistV2Tool: ToolConfig<StarGistParams, any> = {
|
||||
id: 'github_star_gist_v2',
|
||||
name: starGistTool.name,
|
||||
description: starGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: starGistTool.params,
|
||||
request: starGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const starred = response.status === 204
|
||||
return {
|
||||
success: starred,
|
||||
output: {
|
||||
starred,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
starred: { type: 'boolean', description: 'Whether starring succeeded' },
|
||||
gist_id: { type: 'string', description: 'The gist ID' },
|
||||
},
|
||||
}
|
||||
116
apps/sim/tools/github/star_repo.ts
Normal file
116
apps/sim/tools/github/star_repo.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface StarRepoParams {
|
||||
owner: string
|
||||
repo: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface StarRepoResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
starred: boolean
|
||||
owner: string
|
||||
repo: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const starRepoTool: ToolConfig<StarRepoParams, StarRepoResponse> = {
|
||||
id: 'github_star_repo',
|
||||
name: 'GitHub Star Repository',
|
||||
description: 'Star a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/user/starred/${params.owner}/${params.repo}`,
|
||||
method: 'PUT',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Length': '0',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const starred = response.status === 204
|
||||
|
||||
return {
|
||||
success: starred,
|
||||
output: {
|
||||
content: starred
|
||||
? `Successfully starred ${params?.owner}/${params?.repo}`
|
||||
: `Failed to star ${params?.owner}/${params?.repo}`,
|
||||
metadata: {
|
||||
starred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Star operation metadata',
|
||||
properties: {
|
||||
starred: { type: 'boolean', description: 'Whether starring succeeded' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const starRepoV2Tool: ToolConfig<StarRepoParams, any> = {
|
||||
id: 'github_star_repo_v2',
|
||||
name: starRepoTool.name,
|
||||
description: starRepoTool.description,
|
||||
version: '2.0.0',
|
||||
params: starRepoTool.params,
|
||||
request: starRepoTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const starred = response.status === 204
|
||||
return {
|
||||
success: starred,
|
||||
output: {
|
||||
starred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
starred: { type: 'boolean', description: 'Whether starring succeeded' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
}
|
||||
103
apps/sim/tools/github/unstar_gist.ts
Normal file
103
apps/sim/tools/github/unstar_gist.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface UnstarGistParams {
|
||||
gist_id: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface UnstarGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
unstarred: boolean
|
||||
gist_id: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstarGistTool: ToolConfig<UnstarGistParams, UnstarGistResponse> = {
|
||||
id: 'github_unstar_gist',
|
||||
name: 'GitHub Unstar Gist',
|
||||
description: 'Unstar a gist',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID to unstar',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}/star`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const unstarred = response.status === 204
|
||||
|
||||
return {
|
||||
success: unstarred,
|
||||
output: {
|
||||
content: unstarred
|
||||
? `Successfully unstarred gist ${params?.gist_id}`
|
||||
: `Failed to unstar gist ${params?.gist_id}`,
|
||||
metadata: {
|
||||
unstarred,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Unstar operation metadata',
|
||||
properties: {
|
||||
unstarred: { type: 'boolean', description: 'Whether unstarring succeeded' },
|
||||
gist_id: { type: 'string', description: 'The gist ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const unstarGistV2Tool: ToolConfig<UnstarGistParams, any> = {
|
||||
id: 'github_unstar_gist_v2',
|
||||
name: unstarGistTool.name,
|
||||
description: unstarGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: unstarGistTool.params,
|
||||
request: unstarGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const unstarred = response.status === 204
|
||||
return {
|
||||
success: unstarred,
|
||||
output: {
|
||||
unstarred,
|
||||
gist_id: params?.gist_id ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
unstarred: { type: 'boolean', description: 'Whether unstarring succeeded' },
|
||||
gist_id: { type: 'string', description: 'The gist ID' },
|
||||
},
|
||||
}
|
||||
115
apps/sim/tools/github/unstar_repo.ts
Normal file
115
apps/sim/tools/github/unstar_repo.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface UnstarRepoParams {
|
||||
owner: string
|
||||
repo: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface UnstarRepoResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
unstarred: boolean
|
||||
owner: string
|
||||
repo: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstarRepoTool: ToolConfig<UnstarRepoParams, UnstarRepoResponse> = {
|
||||
id: 'github_unstar_repo',
|
||||
name: 'GitHub Unstar Repository',
|
||||
description: 'Remove star from a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/user/starred/${params.owner}/${params.repo}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const unstarred = response.status === 204
|
||||
|
||||
return {
|
||||
success: unstarred,
|
||||
output: {
|
||||
content: unstarred
|
||||
? `Successfully unstarred ${params?.owner}/${params?.repo}`
|
||||
: `Failed to unstar ${params?.owner}/${params?.repo}`,
|
||||
metadata: {
|
||||
unstarred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Unstar operation metadata',
|
||||
properties: {
|
||||
unstarred: { type: 'boolean', description: 'Whether unstarring succeeded' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const unstarRepoV2Tool: ToolConfig<UnstarRepoParams, any> = {
|
||||
id: 'github_unstar_repo_v2',
|
||||
name: unstarRepoTool.name,
|
||||
description: unstarRepoTool.description,
|
||||
version: '2.0.0',
|
||||
params: unstarRepoTool.params,
|
||||
request: unstarRepoTool.request,
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
const unstarred = response.status === 204
|
||||
return {
|
||||
success: unstarred,
|
||||
output: {
|
||||
unstarred,
|
||||
owner: params?.owner ?? '',
|
||||
repo: params?.repo ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
unstarred: { type: 'boolean', description: 'Whether unstarring succeeded' },
|
||||
owner: { type: 'string', description: 'Repository owner' },
|
||||
repo: { type: 'string', description: 'Repository name' },
|
||||
},
|
||||
}
|
||||
164
apps/sim/tools/github/update_gist.ts
Normal file
164
apps/sim/tools/github/update_gist.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface UpdateGistParams {
|
||||
gist_id: string
|
||||
description?: string
|
||||
files?: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface UpdateGistResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: string
|
||||
html_url: string
|
||||
description: string | null
|
||||
public: boolean
|
||||
updated_at: string
|
||||
files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number }
|
||||
>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const updateGistTool: ToolConfig<UpdateGistParams, UpdateGistResponse> = {
|
||||
id: 'github_update_gist',
|
||||
name: 'GitHub Update Gist',
|
||||
description:
|
||||
'Update a gist description or files. To delete a file, set its value to null in files object',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
gist_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The gist ID to update',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New description for the gist',
|
||||
},
|
||||
files: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON object with filenames as keys. Set to null to delete, or provide content to update/add',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.github.com/gists/${params.gist_id?.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {}
|
||||
if (params.description !== undefined) body.description = params.description
|
||||
if (params.files) {
|
||||
body.files = typeof params.files === 'string' ? JSON.parse(params.files) : params.files
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const files: Record<
|
||||
string,
|
||||
{ filename: string; type: string; language: string | null; size: number }
|
||||
> = {}
|
||||
for (const [key, value] of Object.entries(data.files ?? {})) {
|
||||
const file = value as any
|
||||
files[key] = {
|
||||
filename: file.filename,
|
||||
type: file.type,
|
||||
language: file.language ?? null,
|
||||
size: file.size,
|
||||
}
|
||||
}
|
||||
|
||||
const content = `Updated gist: ${data.html_url}
|
||||
Description: ${data.description ?? 'No description'}
|
||||
Files: ${Object.keys(files).join(', ')}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
html_url: data.html_url,
|
||||
description: data.description ?? null,
|
||||
public: data.public,
|
||||
updated_at: data.updated_at,
|
||||
files,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Updated gist metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Current files' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const updateGistV2Tool: ToolConfig<UpdateGistParams, any> = {
|
||||
id: 'github_update_gist_v2',
|
||||
name: updateGistTool.name,
|
||||
description: updateGistTool.description,
|
||||
version: '2.0.0',
|
||||
params: updateGistTool.params,
|
||||
request: updateGistTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
files: data.files ?? {},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Gist ID' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
public: { type: 'boolean', description: 'Is public' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
files: { type: 'object', description: 'Current files' },
|
||||
},
|
||||
}
|
||||
186
apps/sim/tools/github/update_milestone.ts
Normal file
186
apps/sim/tools/github/update_milestone.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface UpdateMilestoneParams {
|
||||
owner: string
|
||||
repo: string
|
||||
milestone_number: number
|
||||
title?: string
|
||||
state?: 'open' | 'closed'
|
||||
description?: string
|
||||
due_on?: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface UpdateMilestoneResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
number: number
|
||||
title: string
|
||||
description: string | null
|
||||
state: string
|
||||
html_url: string
|
||||
due_on: string | null
|
||||
open_issues: number
|
||||
closed_issues: number
|
||||
updated_at: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const updateMilestoneTool: ToolConfig<UpdateMilestoneParams, UpdateMilestoneResponse> = {
|
||||
id: 'github_update_milestone',
|
||||
name: 'GitHub Update Milestone',
|
||||
description: 'Update a milestone in a repository',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
owner: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository owner',
|
||||
},
|
||||
repo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Repository name',
|
||||
},
|
||||
milestone_number: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone number to update',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New milestone title',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New state: open or closed',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New description',
|
||||
},
|
||||
due_on: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New due date (ISO 8601 format)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitHub API token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.github.com/repos/${params.owner}/${params.repo}/milestones/${params.milestone_number}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {}
|
||||
if (params.title !== undefined) body.title = params.title
|
||||
if (params.state !== undefined) body.state = params.state
|
||||
if (params.description !== undefined) body.description = params.description
|
||||
if (params.due_on !== undefined) body.due_on = params.due_on
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
|
||||
const content = `Updated milestone: ${data.title} (#${data.number})
|
||||
State: ${data.state}
|
||||
Due: ${data.due_on ?? 'No due date'}
|
||||
${data.html_url}`
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
metadata: {
|
||||
number: data.number,
|
||||
title: data.title,
|
||||
description: data.description ?? null,
|
||||
state: data.state,
|
||||
html_url: data.html_url,
|
||||
due_on: data.due_on ?? null,
|
||||
open_issues: data.open_issues,
|
||||
closed_issues: data.closed_issues,
|
||||
updated_at: data.updated_at,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Human-readable result' },
|
||||
metadata: {
|
||||
type: 'object',
|
||||
description: 'Updated milestone metadata',
|
||||
properties: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
updated_at: { type: 'string', description: 'Update date' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const updateMilestoneV2Tool: ToolConfig<UpdateMilestoneParams, any> = {
|
||||
id: 'github_update_milestone_v2',
|
||||
name: updateMilestoneTool.name,
|
||||
description: updateMilestoneTool.description,
|
||||
version: '2.0.0',
|
||||
params: updateMilestoneTool.params,
|
||||
request: updateMilestoneTool.request,
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
...data,
|
||||
description: data.description ?? null,
|
||||
due_on: data.due_on ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
number: { type: 'number', description: 'Milestone number' },
|
||||
title: { type: 'string', description: 'Title' },
|
||||
description: { type: 'string', description: 'Description', optional: true },
|
||||
state: { type: 'string', description: 'State' },
|
||||
html_url: { type: 'string', description: 'Web URL' },
|
||||
due_on: { type: 'string', description: 'Due date', optional: true },
|
||||
open_issues: { type: 'number', description: 'Open issues' },
|
||||
closed_issues: { type: 'number', description: 'Closed issues' },
|
||||
},
|
||||
}
|
||||
@@ -14,16 +14,19 @@ export const gitlabCancelPipelineTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
pipelineId: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pipeline ID',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,46 +12,55 @@ export const gitlabCreateIssueTool: ToolConfig<GitLabCreateIssueParams, GitLabCr
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue description (Markdown supported)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
assigneeIds: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of user IDs to assign',
|
||||
},
|
||||
milestoneId: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone ID to assign',
|
||||
},
|
||||
dueDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Due date in YYYY-MM-DD format',
|
||||
},
|
||||
confidential: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the issue is confidential',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,21 +14,25 @@ export const gitlabCreateIssueNoteTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
issueIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue internal ID (IID)',
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment body (Markdown supported)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,61 +17,73 @@ export const gitlabCreateMergeRequestTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
sourceBranch: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Source branch name',
|
||||
},
|
||||
targetBranch: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target branch name',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request description (Markdown supported)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
assigneeIds: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of user IDs to assign',
|
||||
},
|
||||
milestoneId: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone ID to assign',
|
||||
},
|
||||
removeSourceBranch: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Delete source branch after merge',
|
||||
},
|
||||
squash: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Squash commits on merge',
|
||||
},
|
||||
draft: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Mark as draft (work in progress)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,21 +17,25 @@ export const gitlabCreateMergeRequestNoteTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
mergeRequestIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request internal ID (IID)',
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment body (Markdown supported)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,21 +14,25 @@ export const gitlabCreatePipelineTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
ref: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Branch or tag to run the pipeline on',
|
||||
},
|
||||
variables: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of variables for the pipeline (each with key, value, and optional variable_type)',
|
||||
},
|
||||
|
||||
@@ -12,16 +12,19 @@ export const gitlabDeleteIssueTool: ToolConfig<GitLabDeleteIssueParams, GitLabDe
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
issueIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue internal ID (IID)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,16 +11,19 @@ export const gitlabGetIssueTool: ToolConfig<GitLabGetIssueParams, GitLabGetIssue
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
issueIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue number within the project (the # shown in GitLab UI)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,16 +17,19 @@ export const gitlabGetMergeRequestTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
mergeRequestIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request internal ID (IID)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,16 +12,19 @@ export const gitlabGetPipelineTool: ToolConfig<GitLabGetPipelineParams, GitLabGe
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
pipelineId: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pipeline ID',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,11 +11,13 @@ export const gitlabGetProjectTool: ToolConfig<GitLabGetProjectParams, GitLabGetP
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path (e.g., "namespace/project")',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,56 +11,67 @@ export const gitlabListIssuesTool: ToolConfig<GitLabListIssuesParams, GitLabList
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by state (opened, closed, all)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
assigneeId: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by assignee user ID',
|
||||
},
|
||||
milestoneTitle: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by milestone title',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search issues by title and description',
|
||||
},
|
||||
orderBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Order by field (created_at, updated_at)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction (asc, desc)',
|
||||
},
|
||||
perPage: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of results per page (default 20, max 100)',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,51 +17,61 @@ export const gitlabListMergeRequestsTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by state (opened, closed, merged, all)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
sourceBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by source branch',
|
||||
},
|
||||
targetBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by target branch',
|
||||
},
|
||||
orderBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Order by field (created_at, updated_at)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction (asc, desc)',
|
||||
},
|
||||
perPage: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of results per page (default 20, max 100)',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,42 +14,50 @@ export const gitlabListPipelinesTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
ref: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by ref (branch or tag)',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter by status (created, waiting_for_resource, preparing, pending, running, success, failed, canceled, skipped, manual, scheduled)',
|
||||
},
|
||||
orderBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Order by field (id, status, ref, updated_at, user_id)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction (asc, desc)',
|
||||
},
|
||||
perPage: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of results per page (default 20, max 100)',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,46 +14,55 @@ export const gitlabListProjectsTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
owned: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Limit to projects owned by the current user',
|
||||
},
|
||||
membership: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Limit to projects the current user is a member of',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search projects by name',
|
||||
},
|
||||
visibility: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by visibility (public, internal, private)',
|
||||
},
|
||||
orderBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Order by field (id, name, path, created_at, updated_at, last_activity_at)',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort direction (asc, desc)',
|
||||
},
|
||||
perPage: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of results per page (default 20, max 100)',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,41 +17,49 @@ export const gitlabMergeMergeRequestTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
mergeRequestIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request internal ID (IID)',
|
||||
},
|
||||
mergeCommitMessage: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom merge commit message',
|
||||
},
|
||||
squashCommitMessage: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom squash commit message',
|
||||
},
|
||||
squash: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Squash commits before merging',
|
||||
},
|
||||
shouldRemoveSourceBranch: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Delete source branch after merge',
|
||||
},
|
||||
mergeWhenPipelineSucceeds: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge when pipeline succeeds',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,16 +14,19 @@ export const gitlabRetryPipelineTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
pipelineId: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pipeline ID',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,56 +12,67 @@ export const gitlabUpdateIssueTool: ToolConfig<GitLabUpdateIssueParams, GitLabUp
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
issueIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue internal ID (IID)',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New issue title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New issue description (Markdown supported)',
|
||||
},
|
||||
stateEvent: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'State event (close or reopen)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
assigneeIds: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of user IDs to assign',
|
||||
},
|
||||
milestoneId: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone ID to assign',
|
||||
},
|
||||
dueDate: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Due date in YYYY-MM-DD format',
|
||||
},
|
||||
confidential: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the issue is confidential',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,66 +17,79 @@ export const gitlabUpdateMergeRequestTool: ToolConfig<
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'GitLab Personal Access Token',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Project ID or URL-encoded path',
|
||||
},
|
||||
mergeRequestIid: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Merge request internal ID (IID)',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New merge request title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New merge request description',
|
||||
},
|
||||
stateEvent: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'State event (close or reopen)',
|
||||
},
|
||||
labels: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of label names',
|
||||
},
|
||||
assigneeIds: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of user IDs to assign',
|
||||
},
|
||||
milestoneId: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Milestone ID to assign',
|
||||
},
|
||||
targetBranch: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New target branch',
|
||||
},
|
||||
removeSourceBranch: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Delete source branch after merge',
|
||||
},
|
||||
squash: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Squash commits on merge',
|
||||
},
|
||||
draft: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Mark as draft (work in progress)',
|
||||
},
|
||||
},
|
||||
|
||||
135
apps/sim/tools/google_calendar/delete.ts
Normal file
135
apps/sim/tools/google_calendar/delete.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { CALENDAR_API_BASE, type GoogleCalendarDeleteParams } from '@/tools/google_calendar/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GoogleCalendarDeleteResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
eventId: string
|
||||
deleted: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteTool: ToolConfig<GoogleCalendarDeleteParams, GoogleCalendarDeleteResponse> = {
|
||||
id: 'google_calendar_delete',
|
||||
name: 'Google Calendar Delete Event',
|
||||
description: 'Delete an event from Google Calendar',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-calendar',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'Access token for Google Calendar API',
|
||||
},
|
||||
calendarId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Calendar ID (defaults to primary)',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Event ID to delete',
|
||||
},
|
||||
sendUpdates: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'How to send updates to attendees: all, externalOnly, or none',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GoogleCalendarDeleteParams) => {
|
||||
const calendarId = params.calendarId || 'primary'
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.sendUpdates !== undefined) {
|
||||
queryParams.append('sendUpdates', params.sendUpdates)
|
||||
}
|
||||
|
||||
const queryString = queryParams.toString()
|
||||
return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(params.eventId)}${queryString ? `?${queryString}` : ''}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params: GoogleCalendarDeleteParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
// DELETE returns 204 No Content on success
|
||||
if (response.status === 204 || response.ok) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: `Event successfully deleted`,
|
||||
metadata: {
|
||||
eventId: params?.eventId || '',
|
||||
deleted: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error?.message || 'Failed to delete event')
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Event deletion confirmation message' },
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Deletion details including event ID',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
interface GoogleCalendarDeleteV2Response {
|
||||
success: boolean
|
||||
output: {
|
||||
eventId: string
|
||||
deleted: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteV2Tool: ToolConfig<GoogleCalendarDeleteParams, GoogleCalendarDeleteV2Response> =
|
||||
{
|
||||
id: 'google_calendar_delete_v2',
|
||||
name: 'Google Calendar Delete Event',
|
||||
description: 'Delete an event from Google Calendar. Returns API-aligned fields only.',
|
||||
version: '2.0.0',
|
||||
oauth: deleteTool.oauth,
|
||||
params: deleteTool.params,
|
||||
request: deleteTool.request,
|
||||
transformResponse: async (response: Response, params) => {
|
||||
if (response.status === 204 || response.ok) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
eventId: params?.eventId || '',
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error?.message || 'Failed to delete event')
|
||||
},
|
||||
outputs: {
|
||||
eventId: { type: 'string', description: 'Deleted event ID' },
|
||||
deleted: { type: 'boolean', description: 'Whether deletion was successful' },
|
||||
},
|
||||
}
|
||||
@@ -1,17 +1,32 @@
|
||||
import { createTool, createV2Tool } from '@/tools/google_calendar/create'
|
||||
import { deleteTool, deleteV2Tool } from '@/tools/google_calendar/delete'
|
||||
import { getTool, getV2Tool } from '@/tools/google_calendar/get'
|
||||
import { instancesTool, instancesV2Tool } from '@/tools/google_calendar/instances'
|
||||
import { inviteTool, inviteV2Tool } from '@/tools/google_calendar/invite'
|
||||
import { listTool, listV2Tool } from '@/tools/google_calendar/list'
|
||||
import { listCalendarsTool, listCalendarsV2Tool } from '@/tools/google_calendar/list_calendars'
|
||||
import { moveTool, moveV2Tool } from '@/tools/google_calendar/move'
|
||||
import { quickAddTool, quickAddV2Tool } from '@/tools/google_calendar/quick_add'
|
||||
import { updateTool, updateV2Tool } from '@/tools/google_calendar/update'
|
||||
|
||||
export const googleCalendarCreateTool = createTool
|
||||
export const googleCalendarDeleteTool = deleteTool
|
||||
export const googleCalendarGetTool = getTool
|
||||
export const googleCalendarInstancesTool = instancesTool
|
||||
export const googleCalendarInviteTool = inviteTool
|
||||
export const googleCalendarListTool = listTool
|
||||
export const googleCalendarListCalendarsTool = listCalendarsTool
|
||||
export const googleCalendarMoveTool = moveTool
|
||||
export const googleCalendarQuickAddTool = quickAddTool
|
||||
export const googleCalendarUpdateTool = updateTool
|
||||
|
||||
export const googleCalendarCreateV2Tool = createV2Tool
|
||||
export const googleCalendarDeleteV2Tool = deleteV2Tool
|
||||
export const googleCalendarGetV2Tool = getV2Tool
|
||||
export const googleCalendarInstancesV2Tool = instancesV2Tool
|
||||
export const googleCalendarInviteV2Tool = inviteV2Tool
|
||||
export const googleCalendarListV2Tool = listV2Tool
|
||||
export const googleCalendarListCalendarsV2Tool = listCalendarsV2Tool
|
||||
export const googleCalendarMoveV2Tool = moveV2Tool
|
||||
export const googleCalendarQuickAddV2Tool = quickAddV2Tool
|
||||
export const googleCalendarUpdateV2Tool = updateV2Tool
|
||||
|
||||
268
apps/sim/tools/google_calendar/instances.ts
Normal file
268
apps/sim/tools/google_calendar/instances.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
import {
|
||||
CALENDAR_API_BASE,
|
||||
type GoogleCalendarApiEventResponse,
|
||||
} from '@/tools/google_calendar/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GoogleCalendarInstancesParams {
|
||||
accessToken: string
|
||||
calendarId?: string
|
||||
eventId: string
|
||||
timeMin?: string
|
||||
timeMax?: string
|
||||
maxResults?: number
|
||||
pageToken?: string
|
||||
showDeleted?: boolean
|
||||
}
|
||||
|
||||
interface GoogleCalendarInstancesResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
nextPageToken?: string
|
||||
timeZone: string
|
||||
instances: Array<{
|
||||
id: string
|
||||
htmlLink: string
|
||||
status: string
|
||||
summary: string
|
||||
description?: string
|
||||
location?: string
|
||||
start: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
end: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
attendees?: Array<{
|
||||
email: string
|
||||
displayName?: string
|
||||
responseStatus: string
|
||||
}>
|
||||
creator?: {
|
||||
email: string
|
||||
displayName?: string
|
||||
}
|
||||
organizer?: {
|
||||
email: string
|
||||
displayName?: string
|
||||
}
|
||||
recurringEventId: string
|
||||
originalStartTime: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface InstanceApiResponse {
|
||||
kind: string
|
||||
etag: string
|
||||
summary: string
|
||||
description?: string
|
||||
updated: string
|
||||
timeZone: string
|
||||
accessRole: string
|
||||
nextPageToken?: string
|
||||
items: Array<
|
||||
GoogleCalendarApiEventResponse & {
|
||||
recurringEventId: string
|
||||
originalStartTime: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
}
|
||||
>
|
||||
}
|
||||
|
||||
export const instancesTool: ToolConfig<
|
||||
GoogleCalendarInstancesParams,
|
||||
GoogleCalendarInstancesResponse
|
||||
> = {
|
||||
id: 'google_calendar_instances',
|
||||
name: 'Google Calendar Get Instances',
|
||||
description: 'Get instances of a recurring event from Google Calendar',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-calendar',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'Access token for Google Calendar API',
|
||||
},
|
||||
calendarId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Calendar ID (defaults to primary)',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Recurring event ID to get instances of',
|
||||
},
|
||||
timeMin: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lower bound for instances (RFC3339 timestamp, e.g., 2025-06-03T00:00:00Z)',
|
||||
},
|
||||
timeMax: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Upper bound for instances (RFC3339 timestamp, e.g., 2025-06-04T00:00:00Z)',
|
||||
},
|
||||
maxResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of instances to return (default 250, max 2500)',
|
||||
},
|
||||
pageToken: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Token for retrieving subsequent pages of results',
|
||||
},
|
||||
showDeleted: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Include deleted instances',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GoogleCalendarInstancesParams) => {
|
||||
const calendarId = params.calendarId || 'primary'
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.timeMin) queryParams.append('timeMin', params.timeMin)
|
||||
if (params.timeMax) queryParams.append('timeMax', params.timeMax)
|
||||
if (params.maxResults) queryParams.append('maxResults', params.maxResults.toString())
|
||||
if (params.pageToken) queryParams.append('pageToken', params.pageToken)
|
||||
if (params.showDeleted !== undefined)
|
||||
queryParams.append('showDeleted', params.showDeleted.toString())
|
||||
|
||||
const queryString = queryParams.toString()
|
||||
return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(params.eventId)}/instances${queryString ? `?${queryString}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: GoogleCalendarInstancesParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: InstanceApiResponse = await response.json()
|
||||
const instances = data.items || []
|
||||
const instancesCount = instances.length
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: `Found ${instancesCount} instance${instancesCount !== 1 ? 's' : ''} of the recurring event`,
|
||||
metadata: {
|
||||
nextPageToken: data.nextPageToken,
|
||||
timeZone: data.timeZone,
|
||||
instances: instances.map((instance) => ({
|
||||
id: instance.id,
|
||||
htmlLink: instance.htmlLink,
|
||||
status: instance.status,
|
||||
summary: instance.summary || 'No title',
|
||||
description: instance.description,
|
||||
location: instance.location,
|
||||
start: instance.start,
|
||||
end: instance.end,
|
||||
attendees: instance.attendees,
|
||||
creator: instance.creator,
|
||||
organizer: instance.organizer,
|
||||
recurringEventId: instance.recurringEventId,
|
||||
originalStartTime: instance.originalStartTime,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Summary of found instances count' },
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'List of recurring event instances with pagination tokens',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
interface GoogleCalendarInstancesV2Response {
|
||||
success: boolean
|
||||
output: {
|
||||
nextPageToken: string | null
|
||||
timeZone: string | null
|
||||
instances: Array<Record<string, any>>
|
||||
}
|
||||
}
|
||||
|
||||
export const instancesV2Tool: ToolConfig<
|
||||
GoogleCalendarInstancesParams,
|
||||
GoogleCalendarInstancesV2Response
|
||||
> = {
|
||||
id: 'google_calendar_instances_v2',
|
||||
name: 'Google Calendar Get Instances',
|
||||
description:
|
||||
'Get instances of a recurring event from Google Calendar. Returns API-aligned fields only.',
|
||||
version: '2.0.0',
|
||||
oauth: instancesTool.oauth,
|
||||
params: instancesTool.params,
|
||||
request: instancesTool.request,
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: InstanceApiResponse = await response.json()
|
||||
const instances = data.items || []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
nextPageToken: data.nextPageToken ?? null,
|
||||
timeZone: data.timeZone ?? null,
|
||||
instances: instances.map((instance) => ({
|
||||
id: instance.id,
|
||||
htmlLink: instance.htmlLink,
|
||||
status: instance.status,
|
||||
summary: instance.summary ?? null,
|
||||
description: instance.description ?? null,
|
||||
location: instance.location ?? null,
|
||||
start: instance.start,
|
||||
end: instance.end,
|
||||
attendees: instance.attendees ?? null,
|
||||
creator: instance.creator,
|
||||
organizer: instance.organizer,
|
||||
recurringEventId: instance.recurringEventId,
|
||||
originalStartTime: instance.originalStartTime,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
nextPageToken: { type: 'string', description: 'Next page token', optional: true },
|
||||
timeZone: { type: 'string', description: 'Calendar time zone', optional: true },
|
||||
instances: { type: 'json', description: 'List of recurring event instances' },
|
||||
},
|
||||
}
|
||||
280
apps/sim/tools/google_calendar/list_calendars.ts
Normal file
280
apps/sim/tools/google_calendar/list_calendars.ts
Normal file
@@ -0,0 +1,280 @@
|
||||
import { CALENDAR_API_BASE } from '@/tools/google_calendar/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GoogleCalendarListCalendarsParams {
|
||||
accessToken: string
|
||||
minAccessRole?: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
maxResults?: number
|
||||
pageToken?: string
|
||||
showDeleted?: boolean
|
||||
showHidden?: boolean
|
||||
}
|
||||
|
||||
interface CalendarListEntry {
|
||||
kind: string
|
||||
etag: string
|
||||
id: string
|
||||
summary: string
|
||||
description?: string
|
||||
location?: string
|
||||
timeZone: string
|
||||
summaryOverride?: string
|
||||
colorId: string
|
||||
backgroundColor: string
|
||||
foregroundColor: string
|
||||
hidden?: boolean
|
||||
selected?: boolean
|
||||
accessRole: string
|
||||
defaultReminders: Array<{
|
||||
method: string
|
||||
minutes: number
|
||||
}>
|
||||
notificationSettings?: {
|
||||
notifications: Array<{
|
||||
type: string
|
||||
method: string
|
||||
}>
|
||||
}
|
||||
primary?: boolean
|
||||
deleted?: boolean
|
||||
conferenceProperties?: {
|
||||
allowedConferenceSolutionTypes: string[]
|
||||
}
|
||||
}
|
||||
|
||||
interface CalendarListApiResponse {
|
||||
kind: string
|
||||
etag: string
|
||||
nextPageToken?: string
|
||||
nextSyncToken?: string
|
||||
items: CalendarListEntry[]
|
||||
}
|
||||
|
||||
interface GoogleCalendarListCalendarsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
nextPageToken?: string
|
||||
calendars: Array<{
|
||||
id: string
|
||||
summary: string
|
||||
description?: string
|
||||
location?: string
|
||||
timeZone: string
|
||||
accessRole: string
|
||||
backgroundColor: string
|
||||
foregroundColor: string
|
||||
primary?: boolean
|
||||
hidden?: boolean
|
||||
selected?: boolean
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const listCalendarsTool: ToolConfig<
|
||||
GoogleCalendarListCalendarsParams,
|
||||
GoogleCalendarListCalendarsResponse
|
||||
> = {
|
||||
id: 'google_calendar_list_calendars',
|
||||
name: 'Google Calendar List Calendars',
|
||||
description: "List all calendars in the user's calendar list",
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-calendar',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'Access token for Google Calendar API',
|
||||
},
|
||||
minAccessRole: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Minimum access role for returned calendars: freeBusyReader, reader, writer, or owner',
|
||||
},
|
||||
maxResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of calendars to return (default 100, max 250)',
|
||||
},
|
||||
pageToken: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Token for retrieving subsequent pages of results',
|
||||
},
|
||||
showDeleted: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Include deleted calendars',
|
||||
},
|
||||
showHidden: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Include hidden calendars',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GoogleCalendarListCalendarsParams) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.minAccessRole) queryParams.append('minAccessRole', params.minAccessRole)
|
||||
if (params.maxResults) queryParams.append('maxResults', params.maxResults.toString())
|
||||
if (params.pageToken) queryParams.append('pageToken', params.pageToken)
|
||||
if (params.showDeleted !== undefined)
|
||||
queryParams.append('showDeleted', params.showDeleted.toString())
|
||||
if (params.showHidden !== undefined)
|
||||
queryParams.append('showHidden', params.showHidden.toString())
|
||||
|
||||
const queryString = queryParams.toString()
|
||||
return `${CALENDAR_API_BASE}/users/me/calendarList${queryString ? `?${queryString}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: GoogleCalendarListCalendarsParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: CalendarListApiResponse = await response.json()
|
||||
const calendars = data.items || []
|
||||
const calendarsCount = calendars.length
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: `Found ${calendarsCount} calendar${calendarsCount !== 1 ? 's' : ''}`,
|
||||
metadata: {
|
||||
nextPageToken: data.nextPageToken,
|
||||
calendars: calendars.map((calendar) => ({
|
||||
id: calendar.id,
|
||||
summary: calendar.summaryOverride || calendar.summary,
|
||||
description: calendar.description,
|
||||
location: calendar.location,
|
||||
timeZone: calendar.timeZone,
|
||||
accessRole: calendar.accessRole,
|
||||
backgroundColor: calendar.backgroundColor,
|
||||
foregroundColor: calendar.foregroundColor,
|
||||
primary: calendar.primary,
|
||||
hidden: calendar.hidden,
|
||||
selected: calendar.selected,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Summary of found calendars count' },
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'List of calendars with their details',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
interface GoogleCalendarListCalendarsV2Response {
|
||||
success: boolean
|
||||
output: {
|
||||
nextPageToken: string | null
|
||||
calendars: Array<{
|
||||
id: string
|
||||
summary: string
|
||||
description: string | null
|
||||
location: string | null
|
||||
timeZone: string
|
||||
accessRole: string
|
||||
backgroundColor: string
|
||||
foregroundColor: string
|
||||
primary: boolean | null
|
||||
hidden: boolean | null
|
||||
selected: boolean | null
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export const listCalendarsV2Tool: ToolConfig<
|
||||
GoogleCalendarListCalendarsParams,
|
||||
GoogleCalendarListCalendarsV2Response
|
||||
> = {
|
||||
id: 'google_calendar_list_calendars_v2',
|
||||
name: 'Google Calendar List Calendars',
|
||||
description: "List all calendars in the user's calendar list. Returns API-aligned fields only.",
|
||||
version: '2.0.0',
|
||||
oauth: listCalendarsTool.oauth,
|
||||
params: listCalendarsTool.params,
|
||||
request: listCalendarsTool.request,
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: CalendarListApiResponse = await response.json()
|
||||
const calendars = data.items || []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
nextPageToken: data.nextPageToken ?? null,
|
||||
calendars: calendars.map((calendar) => ({
|
||||
id: calendar.id,
|
||||
summary: calendar.summaryOverride || calendar.summary,
|
||||
description: calendar.description ?? null,
|
||||
location: calendar.location ?? null,
|
||||
timeZone: calendar.timeZone,
|
||||
accessRole: calendar.accessRole,
|
||||
backgroundColor: calendar.backgroundColor,
|
||||
foregroundColor: calendar.foregroundColor,
|
||||
primary: calendar.primary ?? null,
|
||||
hidden: calendar.hidden ?? null,
|
||||
selected: calendar.selected ?? null,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
nextPageToken: { type: 'string', description: 'Next page token', optional: true },
|
||||
calendars: {
|
||||
type: 'array',
|
||||
description: 'List of calendars',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Calendar ID' },
|
||||
summary: { type: 'string', description: 'Calendar title' },
|
||||
description: { type: 'string', description: 'Calendar description', optional: true },
|
||||
location: { type: 'string', description: 'Calendar location', optional: true },
|
||||
timeZone: { type: 'string', description: 'Calendar time zone' },
|
||||
accessRole: { type: 'string', description: 'Access role for the calendar' },
|
||||
backgroundColor: { type: 'string', description: 'Calendar background color' },
|
||||
foregroundColor: { type: 'string', description: 'Calendar foreground color' },
|
||||
primary: {
|
||||
type: 'boolean',
|
||||
description: 'Whether this is the primary calendar',
|
||||
optional: true,
|
||||
},
|
||||
hidden: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the calendar is hidden',
|
||||
optional: true,
|
||||
},
|
||||
selected: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the calendar is selected',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
208
apps/sim/tools/google_calendar/move.ts
Normal file
208
apps/sim/tools/google_calendar/move.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import {
|
||||
CALENDAR_API_BASE,
|
||||
type GoogleCalendarApiEventResponse,
|
||||
} from '@/tools/google_calendar/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
interface GoogleCalendarMoveParams {
|
||||
accessToken: string
|
||||
calendarId?: string
|
||||
eventId: string
|
||||
destinationCalendarId: string
|
||||
sendUpdates?: 'all' | 'externalOnly' | 'none'
|
||||
}
|
||||
|
||||
interface GoogleCalendarMoveResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
id: string
|
||||
htmlLink: string
|
||||
status: string
|
||||
summary: string
|
||||
description?: string
|
||||
location?: string
|
||||
start: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
end: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
attendees?: Array<{
|
||||
email: string
|
||||
displayName?: string
|
||||
responseStatus: string
|
||||
}>
|
||||
creator?: {
|
||||
email: string
|
||||
displayName?: string
|
||||
}
|
||||
organizer?: {
|
||||
email: string
|
||||
displayName?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const moveTool: ToolConfig<GoogleCalendarMoveParams, GoogleCalendarMoveResponse> = {
|
||||
id: 'google_calendar_move',
|
||||
name: 'Google Calendar Move Event',
|
||||
description: 'Move an event to a different calendar',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-calendar',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'Access token for Google Calendar API',
|
||||
},
|
||||
calendarId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Source calendar ID (defaults to primary)',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Event ID to move',
|
||||
},
|
||||
destinationCalendarId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Destination calendar ID',
|
||||
},
|
||||
sendUpdates: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'How to send updates to attendees: all, externalOnly, or none',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GoogleCalendarMoveParams) => {
|
||||
const calendarId = params.calendarId || 'primary'
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
queryParams.append('destination', params.destinationCalendarId)
|
||||
|
||||
if (params.sendUpdates !== undefined) {
|
||||
queryParams.append('sendUpdates', params.sendUpdates)
|
||||
}
|
||||
|
||||
return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(params.eventId)}/move?${queryParams.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: GoogleCalendarMoveParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: GoogleCalendarApiEventResponse = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: `Event "${data.summary}" moved successfully`,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
htmlLink: data.htmlLink,
|
||||
status: data.status,
|
||||
summary: data.summary,
|
||||
description: data.description,
|
||||
location: data.location,
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
attendees: data.attendees,
|
||||
creator: data.creator,
|
||||
organizer: data.organizer,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Event move confirmation message' },
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Moved event metadata including new details',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
interface GoogleCalendarMoveV2Response {
|
||||
success: boolean
|
||||
output: {
|
||||
id: string
|
||||
htmlLink: string
|
||||
status: string
|
||||
summary: string | null
|
||||
description: string | null
|
||||
location: string | null
|
||||
start: any
|
||||
end: any
|
||||
attendees: any | null
|
||||
creator: any
|
||||
organizer: any
|
||||
}
|
||||
}
|
||||
|
||||
export const moveV2Tool: ToolConfig<GoogleCalendarMoveParams, GoogleCalendarMoveV2Response> = {
|
||||
id: 'google_calendar_move_v2',
|
||||
name: 'Google Calendar Move Event',
|
||||
description: 'Move an event to a different calendar. Returns API-aligned fields only.',
|
||||
version: '2.0.0',
|
||||
oauth: moveTool.oauth,
|
||||
params: moveTool.params,
|
||||
request: moveTool.request,
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: GoogleCalendarApiEventResponse = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
htmlLink: data.htmlLink,
|
||||
status: data.status,
|
||||
summary: data.summary ?? null,
|
||||
description: data.description ?? null,
|
||||
location: data.location ?? null,
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
attendees: data.attendees ?? null,
|
||||
creator: data.creator,
|
||||
organizer: data.organizer,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Event ID' },
|
||||
htmlLink: { type: 'string', description: 'Event link' },
|
||||
status: { type: 'string', description: 'Event status' },
|
||||
summary: { type: 'string', description: 'Event title', optional: true },
|
||||
description: { type: 'string', description: 'Event description', optional: true },
|
||||
location: { type: 'string', description: 'Event location', optional: true },
|
||||
start: { type: 'json', description: 'Event start' },
|
||||
end: { type: 'json', description: 'Event end' },
|
||||
attendees: { type: 'json', description: 'Event attendees', optional: true },
|
||||
creator: { type: 'json', description: 'Event creator' },
|
||||
organizer: { type: 'json', description: 'Event organizer' },
|
||||
},
|
||||
}
|
||||
@@ -75,6 +75,30 @@ export interface GoogleCalendarInviteParams extends BaseGoogleCalendarParams {
|
||||
replaceExisting?: boolean // Whether to replace existing attendees or add to them
|
||||
}
|
||||
|
||||
export interface GoogleCalendarMoveParams extends BaseGoogleCalendarParams {
|
||||
eventId: string
|
||||
destinationCalendarId: string
|
||||
sendUpdates?: 'all' | 'externalOnly' | 'none'
|
||||
}
|
||||
|
||||
export interface GoogleCalendarInstancesParams extends BaseGoogleCalendarParams {
|
||||
eventId: string
|
||||
timeMin?: string
|
||||
timeMax?: string
|
||||
maxResults?: number
|
||||
pageToken?: string
|
||||
showDeleted?: boolean
|
||||
}
|
||||
|
||||
export interface GoogleCalendarListCalendarsParams {
|
||||
accessToken: string
|
||||
minAccessRole?: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
maxResults?: number
|
||||
pageToken?: string
|
||||
showDeleted?: boolean
|
||||
showHidden?: boolean
|
||||
}
|
||||
|
||||
export type GoogleCalendarToolParams =
|
||||
| GoogleCalendarCreateParams
|
||||
| GoogleCalendarListParams
|
||||
@@ -83,6 +107,9 @@ export type GoogleCalendarToolParams =
|
||||
| GoogleCalendarDeleteParams
|
||||
| GoogleCalendarQuickAddParams
|
||||
| GoogleCalendarInviteParams
|
||||
| GoogleCalendarMoveParams
|
||||
| GoogleCalendarInstancesParams
|
||||
| GoogleCalendarListCalendarsParams
|
||||
|
||||
interface EventMetadata {
|
||||
id: string
|
||||
@@ -277,6 +304,65 @@ export interface GoogleCalendarApiListResponse {
|
||||
items: GoogleCalendarApiEventResponse[]
|
||||
}
|
||||
|
||||
export interface GoogleCalendarDeleteResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
eventId: string
|
||||
deleted: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleCalendarMoveResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
metadata: EventMetadata
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleCalendarInstancesResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
nextPageToken?: string
|
||||
timeZone: string
|
||||
instances: Array<
|
||||
EventMetadata & {
|
||||
recurringEventId: string
|
||||
originalStartTime: {
|
||||
dateTime?: string
|
||||
date?: string
|
||||
timeZone?: string
|
||||
}
|
||||
}
|
||||
>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleCalendarListCalendarsResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
metadata: {
|
||||
nextPageToken?: string
|
||||
calendars: Array<{
|
||||
id: string
|
||||
summary: string
|
||||
description?: string
|
||||
location?: string
|
||||
timeZone: string
|
||||
accessRole: string
|
||||
backgroundColor: string
|
||||
foregroundColor: string
|
||||
primary?: boolean
|
||||
hidden?: boolean
|
||||
selected?: boolean
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type GoogleCalendarResponse =
|
||||
| GoogleCalendarCreateResponse
|
||||
| GoogleCalendarListResponse
|
||||
@@ -284,3 +370,7 @@ export type GoogleCalendarResponse =
|
||||
| GoogleCalendarQuickAddResponse
|
||||
| GoogleCalendarInviteResponse
|
||||
| GoogleCalendarUpdateResponse
|
||||
| GoogleCalendarDeleteResponse
|
||||
| GoogleCalendarMoveResponse
|
||||
| GoogleCalendarInstancesResponse
|
||||
| GoogleCalendarListCalendarsResponse
|
||||
|
||||
255
apps/sim/tools/google_calendar/update.ts
Normal file
255
apps/sim/tools/google_calendar/update.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
import {
|
||||
CALENDAR_API_BASE,
|
||||
type GoogleCalendarApiEventResponse,
|
||||
type GoogleCalendarUpdateParams,
|
||||
type GoogleCalendarUpdateResponse,
|
||||
} from '@/tools/google_calendar/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const updateTool: ToolConfig<GoogleCalendarUpdateParams, GoogleCalendarUpdateResponse> = {
|
||||
id: 'google_calendar_update',
|
||||
name: 'Google Calendar Update Event',
|
||||
description: 'Update an existing event in Google Calendar',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-calendar',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'Access token for Google Calendar API',
|
||||
},
|
||||
calendarId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Calendar ID (defaults to primary)',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Event ID to update',
|
||||
},
|
||||
summary: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New event title/summary',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New event description',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New event location',
|
||||
},
|
||||
startDateTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'New start date and time. MUST include timezone offset (e.g., 2025-06-03T10:00:00-08:00) OR provide timeZone parameter',
|
||||
},
|
||||
endDateTime: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'New end date and time. MUST include timezone offset (e.g., 2025-06-03T11:00:00-08:00) OR provide timeZone parameter',
|
||||
},
|
||||
timeZone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Time zone (e.g., America/Los_Angeles). Required if datetime does not include offset.',
|
||||
},
|
||||
attendees: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of attendee email addresses (replaces existing attendees)',
|
||||
},
|
||||
sendUpdates: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'How to send updates to attendees: all, externalOnly, or none',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GoogleCalendarUpdateParams) => {
|
||||
const calendarId = params.calendarId || 'primary'
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.sendUpdates !== undefined) {
|
||||
queryParams.append('sendUpdates', params.sendUpdates)
|
||||
}
|
||||
|
||||
const queryString = queryParams.toString()
|
||||
return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(params.eventId)}${queryString ? `?${queryString}` : ''}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: GoogleCalendarUpdateParams) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: GoogleCalendarUpdateParams) => {
|
||||
const updateData: Record<string, unknown> = {}
|
||||
|
||||
if (params.summary !== undefined) {
|
||||
updateData.summary = params.summary
|
||||
}
|
||||
|
||||
if (params.description !== undefined) {
|
||||
updateData.description = params.description
|
||||
}
|
||||
|
||||
if (params.location !== undefined) {
|
||||
updateData.location = params.location
|
||||
}
|
||||
|
||||
if (params.startDateTime !== undefined) {
|
||||
const needsTimezone =
|
||||
!params.startDateTime.includes('+') && !params.startDateTime.includes('-', 10)
|
||||
updateData.start = {
|
||||
dateTime: params.startDateTime,
|
||||
...(needsTimezone && params.timeZone ? { timeZone: params.timeZone } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
if (params.endDateTime !== undefined) {
|
||||
const needsTimezone =
|
||||
!params.endDateTime.includes('+') && !params.endDateTime.includes('-', 10)
|
||||
updateData.end = {
|
||||
dateTime: params.endDateTime,
|
||||
...(needsTimezone && params.timeZone ? { timeZone: params.timeZone } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
// Handle attendees - convert to array format
|
||||
if (params.attendees !== undefined) {
|
||||
let attendeeList: string[] = []
|
||||
const attendees = params.attendees as string | string[]
|
||||
|
||||
if (Array.isArray(attendees)) {
|
||||
attendeeList = attendees.filter((email: string) => email && email.trim().length > 0)
|
||||
} else if (typeof attendees === 'string' && attendees.trim().length > 0) {
|
||||
attendeeList = attendees
|
||||
.split(',')
|
||||
.map((email: string) => email.trim())
|
||||
.filter((email: string) => email.length > 0)
|
||||
}
|
||||
|
||||
updateData.attendees = attendeeList.map((email: string) => ({ email }))
|
||||
}
|
||||
|
||||
return updateData
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: GoogleCalendarApiEventResponse = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: `Event "${data.summary}" updated successfully`,
|
||||
metadata: {
|
||||
id: data.id,
|
||||
htmlLink: data.htmlLink,
|
||||
status: data.status,
|
||||
summary: data.summary,
|
||||
description: data.description,
|
||||
location: data.location,
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
attendees: data.attendees,
|
||||
creator: data.creator,
|
||||
organizer: data.organizer,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Event update confirmation message' },
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Updated event metadata including ID, status, and details',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
interface GoogleCalendarUpdateV2Response {
|
||||
success: boolean
|
||||
output: {
|
||||
id: string
|
||||
htmlLink: string
|
||||
status: string
|
||||
summary: string | null
|
||||
description: string | null
|
||||
location: string | null
|
||||
start: any
|
||||
end: any
|
||||
attendees: any | null
|
||||
creator: any
|
||||
organizer: any
|
||||
}
|
||||
}
|
||||
|
||||
export const updateV2Tool: ToolConfig<GoogleCalendarUpdateParams, GoogleCalendarUpdateV2Response> =
|
||||
{
|
||||
id: 'google_calendar_update_v2',
|
||||
name: 'Google Calendar Update Event',
|
||||
description: 'Update an existing event in Google Calendar. Returns API-aligned fields only.',
|
||||
version: '2.0.0',
|
||||
oauth: updateTool.oauth,
|
||||
params: updateTool.params,
|
||||
request: updateTool.request,
|
||||
transformResponse: async (response: Response) => {
|
||||
const data: GoogleCalendarApiEventResponse = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
htmlLink: data.htmlLink,
|
||||
status: data.status,
|
||||
summary: data.summary ?? null,
|
||||
description: data.description ?? null,
|
||||
location: data.location ?? null,
|
||||
start: data.start,
|
||||
end: data.end,
|
||||
attendees: data.attendees ?? null,
|
||||
creator: data.creator,
|
||||
organizer: data.organizer,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
id: { type: 'string', description: 'Event ID' },
|
||||
htmlLink: { type: 'string', description: 'Event link' },
|
||||
status: { type: 'string', description: 'Event status' },
|
||||
summary: { type: 'string', description: 'Event title', optional: true },
|
||||
description: { type: 'string', description: 'Event description', optional: true },
|
||||
location: { type: 'string', description: 'Event location', optional: true },
|
||||
start: { type: 'json', description: 'Event start' },
|
||||
end: { type: 'json', description: 'Event end' },
|
||||
attendees: { type: 'json', description: 'Event attendees', optional: true },
|
||||
creator: { type: 'json', description: 'Event creator' },
|
||||
organizer: { type: 'json', description: 'Event organizer' },
|
||||
},
|
||||
}
|
||||
111
apps/sim/tools/google_drive/copy.ts
Normal file
111
apps/sim/tools/google_drive/copy.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import type { GoogleDriveFile, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import { ALL_FILE_FIELDS } from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveCopyParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
newName?: string
|
||||
destinationFolderId?: string
|
||||
}
|
||||
|
||||
interface GoogleDriveCopyResponse extends ToolResponse {
|
||||
output: {
|
||||
file: GoogleDriveFile
|
||||
}
|
||||
}
|
||||
|
||||
export const copyTool: ToolConfig<GoogleDriveCopyParams, GoogleDriveCopyResponse> = {
|
||||
id: 'google_drive_copy',
|
||||
name: 'Copy Google Drive File',
|
||||
description: 'Create a copy of a file in Google Drive',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to copy',
|
||||
},
|
||||
newName: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name for the copied file (defaults to "Copy of [original name]")',
|
||||
},
|
||||
destinationFolderId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the folder to place the copy in (defaults to same location as original)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}/copy`)
|
||||
url.searchParams.append('fields', ALL_FILE_FIELDS)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.newName) {
|
||||
body.name = params.newName
|
||||
}
|
||||
if (params.destinationFolderId) {
|
||||
body.parents = [params.destinationFolderId.trim()]
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to copy Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
file: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'json',
|
||||
description: 'The copied file metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Google Drive file ID of the copy' },
|
||||
name: { type: 'string', description: 'File name' },
|
||||
mimeType: { type: 'string', description: 'MIME type' },
|
||||
webViewLink: { type: 'string', description: 'URL to view in browser' },
|
||||
parents: { type: 'json', description: 'Parent folder IDs' },
|
||||
createdTime: { type: 'string', description: 'File creation time' },
|
||||
modifiedTime: { type: 'string', description: 'Last modification time' },
|
||||
owners: { type: 'json', description: 'List of file owners' },
|
||||
size: { type: 'string', description: 'File size in bytes' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
78
apps/sim/tools/google_drive/delete.ts
Normal file
78
apps/sim/tools/google_drive/delete.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveDeleteParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveDeleteResponse extends ToolResponse {
|
||||
output: {
|
||||
deleted: boolean
|
||||
fileId: string
|
||||
}
|
||||
}
|
||||
|
||||
export const deleteTool: ToolConfig<GoogleDriveDeleteParams, GoogleDriveDeleteResponse> = {
|
||||
id: 'google_drive_delete',
|
||||
name: 'Delete Google Drive File',
|
||||
description: 'Permanently delete a file from Google Drive (bypasses trash)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to permanently delete',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}`)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
if (!response.ok) {
|
||||
const data = await response.json()
|
||||
throw new Error(data.error?.message || 'Failed to delete Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
deleted: true,
|
||||
fileId: params?.fileId ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the file was successfully deleted',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
description: 'The ID of the deleted file',
|
||||
},
|
||||
},
|
||||
}
|
||||
137
apps/sim/tools/google_drive/get_about.ts
Normal file
137
apps/sim/tools/google_drive/get_about.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import type { GoogleDriveToolParams, GoogleDriveUser } from '@/tools/google_drive/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveGetAboutParams extends GoogleDriveToolParams {}
|
||||
|
||||
interface GoogleDriveGetAboutResponse extends ToolResponse {
|
||||
output: {
|
||||
user: GoogleDriveUser & {
|
||||
emailAddress: string
|
||||
}
|
||||
storageQuota: {
|
||||
limit: string | null
|
||||
usage: string
|
||||
usageInDrive: string
|
||||
usageInDriveTrash: string
|
||||
}
|
||||
canCreateDrives: boolean
|
||||
importFormats: Record<string, string[]>
|
||||
exportFormats: Record<string, string[]>
|
||||
maxUploadSize: string
|
||||
}
|
||||
}
|
||||
|
||||
export const getAboutTool: ToolConfig<GoogleDriveGetAboutParams, GoogleDriveGetAboutResponse> = {
|
||||
id: 'google_drive_get_about',
|
||||
name: 'Get Google Drive Info',
|
||||
description:
|
||||
'Get information about the user and their Google Drive (storage quota, capabilities)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: () => {
|
||||
const url = new URL('https://www.googleapis.com/drive/v3/about')
|
||||
url.searchParams.append(
|
||||
'fields',
|
||||
'user,storageQuota,canCreateDrives,importFormats,exportFormats,maxUploadSize'
|
||||
)
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to get Google Drive info')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
user: {
|
||||
displayName: data.user?.displayName ?? null,
|
||||
emailAddress: data.user?.emailAddress ?? '',
|
||||
photoLink: data.user?.photoLink ?? null,
|
||||
permissionId: data.user?.permissionId ?? null,
|
||||
me: data.user?.me ?? true,
|
||||
},
|
||||
storageQuota: {
|
||||
limit: data.storageQuota?.limit ?? null,
|
||||
usage: data.storageQuota?.usage ?? '0',
|
||||
usageInDrive: data.storageQuota?.usageInDrive ?? '0',
|
||||
usageInDriveTrash: data.storageQuota?.usageInDriveTrash ?? '0',
|
||||
},
|
||||
canCreateDrives: data.canCreateDrives ?? false,
|
||||
importFormats: data.importFormats ?? {},
|
||||
exportFormats: data.exportFormats ?? {},
|
||||
maxUploadSize: data.maxUploadSize ?? '0',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
user: {
|
||||
type: 'json',
|
||||
description: 'Information about the authenticated user',
|
||||
properties: {
|
||||
displayName: { type: 'string', description: 'User display name' },
|
||||
emailAddress: { type: 'string', description: 'User email address' },
|
||||
photoLink: { type: 'string', description: 'URL to user profile photo', optional: true },
|
||||
permissionId: { type: 'string', description: 'User permission ID' },
|
||||
me: { type: 'boolean', description: 'Whether this is the authenticated user' },
|
||||
},
|
||||
},
|
||||
storageQuota: {
|
||||
type: 'json',
|
||||
description: 'Storage quota information in bytes',
|
||||
properties: {
|
||||
limit: {
|
||||
type: 'string',
|
||||
description: 'Total storage limit in bytes (null for unlimited)',
|
||||
optional: true,
|
||||
},
|
||||
usage: { type: 'string', description: 'Total storage used in bytes' },
|
||||
usageInDrive: { type: 'string', description: 'Storage used by Drive files in bytes' },
|
||||
usageInDriveTrash: {
|
||||
type: 'string',
|
||||
description: 'Storage used by trashed files in bytes',
|
||||
},
|
||||
},
|
||||
},
|
||||
canCreateDrives: {
|
||||
type: 'boolean',
|
||||
description: 'Whether user can create shared drives',
|
||||
},
|
||||
importFormats: {
|
||||
type: 'json',
|
||||
description: 'Map of MIME types that can be imported and their target formats',
|
||||
},
|
||||
exportFormats: {
|
||||
type: 'json',
|
||||
description: 'Map of Google Workspace MIME types and their exportable formats',
|
||||
},
|
||||
maxUploadSize: {
|
||||
type: 'string',
|
||||
description: 'Maximum upload size in bytes',
|
||||
},
|
||||
},
|
||||
}
|
||||
99
apps/sim/tools/google_drive/get_file.ts
Normal file
99
apps/sim/tools/google_drive/get_file.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import type { GoogleDriveFile, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import { ALL_FILE_FIELDS } from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveGetFileParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveGetFileResponse extends ToolResponse {
|
||||
output: {
|
||||
file: GoogleDriveFile
|
||||
}
|
||||
}
|
||||
|
||||
export const getFileTool: ToolConfig<GoogleDriveGetFileParams, GoogleDriveGetFileResponse> = {
|
||||
id: 'google_drive_get_file',
|
||||
name: 'Get Google Drive File',
|
||||
description: 'Get metadata for a specific file in Google Drive by its ID',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to retrieve',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}`)
|
||||
url.searchParams.append('fields', ALL_FILE_FIELDS)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to get Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
file: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'json',
|
||||
description: 'The file metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Google Drive file ID' },
|
||||
name: { type: 'string', description: 'File name' },
|
||||
mimeType: { type: 'string', description: 'MIME type' },
|
||||
description: { type: 'string', description: 'File description', optional: true },
|
||||
size: { type: 'string', description: 'File size in bytes', optional: true },
|
||||
starred: { type: 'boolean', description: 'Whether file is starred' },
|
||||
trashed: { type: 'boolean', description: 'Whether file is in trash' },
|
||||
webViewLink: { type: 'string', description: 'URL to view in browser' },
|
||||
webContentLink: { type: 'string', description: 'Direct download URL', optional: true },
|
||||
iconLink: { type: 'string', description: 'URL to file icon' },
|
||||
thumbnailLink: { type: 'string', description: 'URL to thumbnail', optional: true },
|
||||
parents: { type: 'json', description: 'Parent folder IDs' },
|
||||
owners: { type: 'json', description: 'List of file owners' },
|
||||
permissions: { type: 'json', description: 'File permissions', optional: true },
|
||||
createdTime: { type: 'string', description: 'File creation time' },
|
||||
modifiedTime: { type: 'string', description: 'Last modification time' },
|
||||
lastModifyingUser: { type: 'json', description: 'User who last modified the file' },
|
||||
shared: { type: 'boolean', description: 'Whether file is shared' },
|
||||
ownedByMe: { type: 'boolean', description: 'Whether owned by current user' },
|
||||
capabilities: { type: 'json', description: 'User capabilities on file' },
|
||||
md5Checksum: { type: 'string', description: 'MD5 hash', optional: true },
|
||||
version: { type: 'string', description: 'Version number' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,11 +1,31 @@
|
||||
import { copyTool } from '@/tools/google_drive/copy'
|
||||
import { createFolderTool } from '@/tools/google_drive/create_folder'
|
||||
import { deleteTool } from '@/tools/google_drive/delete'
|
||||
import { downloadTool } from '@/tools/google_drive/download'
|
||||
import { getAboutTool } from '@/tools/google_drive/get_about'
|
||||
import { getContentTool } from '@/tools/google_drive/get_content'
|
||||
import { getFileTool } from '@/tools/google_drive/get_file'
|
||||
import { listTool } from '@/tools/google_drive/list'
|
||||
import { listPermissionsTool } from '@/tools/google_drive/list_permissions'
|
||||
import { shareTool } from '@/tools/google_drive/share'
|
||||
import { trashTool } from '@/tools/google_drive/trash'
|
||||
import { unshareTool } from '@/tools/google_drive/unshare'
|
||||
import { untrashTool } from '@/tools/google_drive/untrash'
|
||||
import { updateTool } from '@/tools/google_drive/update'
|
||||
import { uploadTool } from '@/tools/google_drive/upload'
|
||||
|
||||
export const googleDriveCopyTool = copyTool
|
||||
export const googleDriveCreateFolderTool = createFolderTool
|
||||
export const googleDriveDeleteTool = deleteTool
|
||||
export const googleDriveDownloadTool = downloadTool
|
||||
export const googleDriveGetAboutTool = getAboutTool
|
||||
export const googleDriveGetContentTool = getContentTool
|
||||
export const googleDriveGetFileTool = getFileTool
|
||||
export const googleDriveListTool = listTool
|
||||
export const googleDriveListPermissionsTool = listPermissionsTool
|
||||
export const googleDriveShareTool = shareTool
|
||||
export const googleDriveTrashTool = trashTool
|
||||
export const googleDriveUnshareTool = unshareTool
|
||||
export const googleDriveUntrashTool = untrashTool
|
||||
export const googleDriveUpdateTool = updateTool
|
||||
export const googleDriveUploadTool = uploadTool
|
||||
|
||||
124
apps/sim/tools/google_drive/list_permissions.ts
Normal file
124
apps/sim/tools/google_drive/list_permissions.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import type { GoogleDrivePermission, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveListPermissionsParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveListPermissionsResponse extends ToolResponse {
|
||||
output: {
|
||||
permissions: GoogleDrivePermission[]
|
||||
}
|
||||
}
|
||||
|
||||
export const listPermissionsTool: ToolConfig<
|
||||
GoogleDriveListPermissionsParams,
|
||||
GoogleDriveListPermissionsResponse
|
||||
> = {
|
||||
id: 'google_drive_list_permissions',
|
||||
name: 'List Google Drive Permissions',
|
||||
description: 'List all permissions (who has access) for a file in Google Drive',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to list permissions for',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}/permissions`
|
||||
)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
url.searchParams.append(
|
||||
'fields',
|
||||
'permissions(id,type,role,emailAddress,displayName,photoLink,domain,expirationTime,deleted,allowFileDiscovery,pendingOwner,permissionDetails)'
|
||||
)
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to list Google Drive permissions')
|
||||
}
|
||||
|
||||
const permissions = (data.permissions ?? []).map((p: Record<string, unknown>) => ({
|
||||
id: p.id ?? null,
|
||||
type: p.type ?? null,
|
||||
role: p.role ?? null,
|
||||
emailAddress: p.emailAddress ?? null,
|
||||
displayName: p.displayName ?? null,
|
||||
photoLink: p.photoLink ?? null,
|
||||
domain: p.domain ?? null,
|
||||
expirationTime: p.expirationTime ?? null,
|
||||
deleted: p.deleted ?? false,
|
||||
allowFileDiscovery: p.allowFileDiscovery ?? null,
|
||||
pendingOwner: p.pendingOwner ?? false,
|
||||
permissionDetails: p.permissionDetails ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
permissions,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
permissions: {
|
||||
type: 'array',
|
||||
description: 'List of permissions on the file',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Permission ID (use to remove permission)' },
|
||||
type: { type: 'string', description: 'Grantee type (user, group, domain, anyone)' },
|
||||
role: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Permission role (owner, organizer, fileOrganizer, writer, commenter, reader)',
|
||||
},
|
||||
emailAddress: { type: 'string', description: 'Email of the grantee' },
|
||||
displayName: { type: 'string', description: 'Display name of the grantee' },
|
||||
photoLink: { type: 'string', description: 'Photo URL of the grantee' },
|
||||
domain: { type: 'string', description: 'Domain of the grantee' },
|
||||
expirationTime: { type: 'string', description: 'When permission expires' },
|
||||
deleted: { type: 'boolean', description: 'Whether grantee account is deleted' },
|
||||
allowFileDiscovery: {
|
||||
type: 'boolean',
|
||||
description: 'Whether file is discoverable by grantee',
|
||||
},
|
||||
pendingOwner: { type: 'boolean', description: 'Whether ownership transfer is pending' },
|
||||
permissionDetails: {
|
||||
type: 'json',
|
||||
description: 'Details about inherited permissions',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
178
apps/sim/tools/google_drive/share.ts
Normal file
178
apps/sim/tools/google_drive/share.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import type { GoogleDrivePermission, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveShareParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
email?: string
|
||||
domain?: string
|
||||
type: 'user' | 'group' | 'domain' | 'anyone'
|
||||
role: 'owner' | 'organizer' | 'fileOrganizer' | 'writer' | 'commenter' | 'reader'
|
||||
transferOwnership?: boolean
|
||||
moveToNewOwnersRoot?: boolean
|
||||
sendNotification?: boolean
|
||||
emailMessage?: string
|
||||
}
|
||||
|
||||
interface GoogleDriveShareResponse extends ToolResponse {
|
||||
output: {
|
||||
permission: GoogleDrivePermission
|
||||
}
|
||||
}
|
||||
|
||||
export const shareTool: ToolConfig<GoogleDriveShareParams, GoogleDriveShareResponse> = {
|
||||
id: 'google_drive_share',
|
||||
name: 'Share Google Drive File',
|
||||
description: 'Share a file with a user, group, domain, or make it public',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to share',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Type of grantee: user, group, domain, or anyone',
|
||||
},
|
||||
role: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Permission role: owner (transfer ownership), organizer (shared drive only), fileOrganizer (shared drive only), writer (edit), commenter (view and comment), reader (view only)',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email address of the user or group (required for type=user or type=group)',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain to share with (required for type=domain)',
|
||||
},
|
||||
transferOwnership: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Required when role is owner. Transfers ownership to the specified user.',
|
||||
},
|
||||
moveToNewOwnersRoot: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
"When transferring ownership, move the file to the new owner's My Drive root folder.",
|
||||
},
|
||||
sendNotification: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to send an email notification (default: true)',
|
||||
},
|
||||
emailMessage: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom message to include in the notification email',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}/permissions`
|
||||
)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
if (params.transferOwnership) {
|
||||
url.searchParams.append('transferOwnership', 'true')
|
||||
}
|
||||
if (params.moveToNewOwnersRoot) {
|
||||
url.searchParams.append('moveToNewOwnersRoot', 'true')
|
||||
}
|
||||
if (params.sendNotification !== undefined) {
|
||||
url.searchParams.append('sendNotificationEmail', String(params.sendNotification))
|
||||
}
|
||||
if (params.emailMessage) {
|
||||
url.searchParams.append('emailMessage', params.emailMessage)
|
||||
}
|
||||
return url.toString()
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {
|
||||
type: params.type,
|
||||
role: params.role,
|
||||
}
|
||||
if (params.email) {
|
||||
body.emailAddress = params.email.trim()
|
||||
}
|
||||
if (params.domain) {
|
||||
body.domain = params.domain.trim()
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to share Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
permission: {
|
||||
id: data.id ?? null,
|
||||
type: data.type ?? null,
|
||||
role: data.role ?? null,
|
||||
emailAddress: data.emailAddress ?? null,
|
||||
displayName: data.displayName ?? null,
|
||||
domain: data.domain ?? null,
|
||||
expirationTime: data.expirationTime ?? null,
|
||||
deleted: data.deleted ?? false,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
permission: {
|
||||
type: 'json',
|
||||
description: 'The created permission details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Permission ID' },
|
||||
type: { type: 'string', description: 'Grantee type (user, group, domain, anyone)' },
|
||||
role: { type: 'string', description: 'Permission role' },
|
||||
emailAddress: { type: 'string', description: 'Email of the grantee', optional: true },
|
||||
displayName: { type: 'string', description: 'Display name of the grantee', optional: true },
|
||||
domain: { type: 'string', description: 'Domain of the grantee', optional: true },
|
||||
expirationTime: { type: 'string', description: 'Expiration time', optional: true },
|
||||
deleted: { type: 'boolean', description: 'Whether grantee is deleted' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
87
apps/sim/tools/google_drive/trash.ts
Normal file
87
apps/sim/tools/google_drive/trash.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import type { GoogleDriveFile, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import { ALL_FILE_FIELDS } from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveTrashParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveTrashResponse extends ToolResponse {
|
||||
output: {
|
||||
file: GoogleDriveFile
|
||||
}
|
||||
}
|
||||
|
||||
export const trashTool: ToolConfig<GoogleDriveTrashParams, GoogleDriveTrashResponse> = {
|
||||
id: 'google_drive_trash',
|
||||
name: 'Trash Google Drive File',
|
||||
description: 'Move a file to the trash in Google Drive (can be restored later)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to move to trash',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}`)
|
||||
url.searchParams.append('fields', ALL_FILE_FIELDS)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: () => ({
|
||||
trashed: true,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to trash Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
file: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'json',
|
||||
description: 'The trashed file metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Google Drive file ID' },
|
||||
name: { type: 'string', description: 'File name' },
|
||||
mimeType: { type: 'string', description: 'MIME type' },
|
||||
trashed: { type: 'boolean', description: 'Whether file is in trash (should be true)' },
|
||||
trashedTime: { type: 'string', description: 'When file was trashed' },
|
||||
webViewLink: { type: 'string', description: 'URL to view in browser' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
93
apps/sim/tools/google_drive/unshare.ts
Normal file
93
apps/sim/tools/google_drive/unshare.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveUnshareParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
permissionId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveUnshareResponse extends ToolResponse {
|
||||
output: {
|
||||
removed: boolean
|
||||
fileId: string
|
||||
permissionId: string
|
||||
}
|
||||
}
|
||||
|
||||
export const unshareTool: ToolConfig<GoogleDriveUnshareParams, GoogleDriveUnshareResponse> = {
|
||||
id: 'google_drive_unshare',
|
||||
name: 'Unshare Google Drive File',
|
||||
description: 'Remove a permission from a file (revoke access)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to modify permissions on',
|
||||
},
|
||||
permissionId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the permission to remove (use list_permissions to find this)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(
|
||||
`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}/permissions/${params.permissionId?.trim()}`
|
||||
)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params) => {
|
||||
if (!response.ok) {
|
||||
const data = await response.json()
|
||||
throw new Error(data.error?.message || 'Failed to remove permission from Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
removed: true,
|
||||
fileId: params?.fileId ?? '',
|
||||
permissionId: params?.permissionId ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
removed: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the permission was successfully removed',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
description: 'The ID of the file',
|
||||
},
|
||||
permissionId: {
|
||||
type: 'string',
|
||||
description: 'The ID of the removed permission',
|
||||
},
|
||||
},
|
||||
}
|
||||
87
apps/sim/tools/google_drive/untrash.ts
Normal file
87
apps/sim/tools/google_drive/untrash.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import type { GoogleDriveFile, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import { ALL_FILE_FIELDS } from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveUntrashParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
}
|
||||
|
||||
interface GoogleDriveUntrashResponse extends ToolResponse {
|
||||
output: {
|
||||
file: GoogleDriveFile
|
||||
}
|
||||
}
|
||||
|
||||
export const untrashTool: ToolConfig<GoogleDriveUntrashParams, GoogleDriveUntrashResponse> = {
|
||||
id: 'google_drive_untrash',
|
||||
name: 'Restore Google Drive File',
|
||||
description: 'Restore a file from the trash in Google Drive',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to restore from trash',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}`)
|
||||
url.searchParams.append('fields', ALL_FILE_FIELDS)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
return url.toString()
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: () => ({
|
||||
trashed: false,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to restore Google Drive file from trash')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
file: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'json',
|
||||
description: 'The restored file metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Google Drive file ID' },
|
||||
name: { type: 'string', description: 'File name' },
|
||||
mimeType: { type: 'string', description: 'MIME type' },
|
||||
trashed: { type: 'boolean', description: 'Whether file is in trash (should be false)' },
|
||||
webViewLink: { type: 'string', description: 'URL to view in browser' },
|
||||
parents: { type: 'json', description: 'Parent folder IDs' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
140
apps/sim/tools/google_drive/update.ts
Normal file
140
apps/sim/tools/google_drive/update.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import type { GoogleDriveFile, GoogleDriveToolParams } from '@/tools/google_drive/types'
|
||||
import { ALL_FILE_FIELDS } from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig, ToolResponse } from '@/tools/types'
|
||||
|
||||
interface GoogleDriveUpdateParams extends GoogleDriveToolParams {
|
||||
fileId: string
|
||||
name?: string
|
||||
description?: string
|
||||
addParents?: string
|
||||
removeParents?: string
|
||||
starred?: boolean
|
||||
}
|
||||
|
||||
interface GoogleDriveUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
file: GoogleDriveFile
|
||||
}
|
||||
}
|
||||
|
||||
export const updateTool: ToolConfig<GoogleDriveUpdateParams, GoogleDriveUpdateResponse> = {
|
||||
id: 'google_drive_update',
|
||||
name: 'Update Google Drive File',
|
||||
description: 'Update file metadata in Google Drive (rename, move, star, add description)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'google-drive',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token',
|
||||
},
|
||||
fileId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the file to update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New name for the file',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New description for the file',
|
||||
},
|
||||
addParents: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of parent folder IDs to add (moves file to these folders)',
|
||||
},
|
||||
removeParents: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of parent folder IDs to remove',
|
||||
},
|
||||
starred: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to star or unstar the file',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const url = new URL(`https://www.googleapis.com/drive/v3/files/${params.fileId?.trim()}`)
|
||||
url.searchParams.append('fields', ALL_FILE_FIELDS)
|
||||
url.searchParams.append('supportsAllDrives', 'true')
|
||||
if (params.addParents) {
|
||||
url.searchParams.append('addParents', params.addParents.trim())
|
||||
}
|
||||
if (params.removeParents) {
|
||||
url.searchParams.append('removeParents', params.removeParents.trim())
|
||||
}
|
||||
return url.toString()
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name !== undefined) {
|
||||
body.name = params.name
|
||||
}
|
||||
if (params.description !== undefined) {
|
||||
body.description = params.description
|
||||
}
|
||||
if (params.starred !== undefined) {
|
||||
body.starred = params.starred
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error?.message || 'Failed to update Google Drive file')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
file: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
file: {
|
||||
type: 'json',
|
||||
description: 'The updated file metadata',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Google Drive file ID' },
|
||||
name: { type: 'string', description: 'File name' },
|
||||
mimeType: { type: 'string', description: 'MIME type' },
|
||||
description: { type: 'string', description: 'File description', optional: true },
|
||||
starred: { type: 'boolean', description: 'Whether file is starred' },
|
||||
webViewLink: { type: 'string', description: 'URL to view in browser' },
|
||||
parents: { type: 'json', description: 'Parent folder IDs' },
|
||||
modifiedTime: { type: 'string', description: 'Last modification time' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user