feat(google-tasks): add Google Tasks integration (#3342)

* feat(google-tasks): add Google Tasks integration

* fix(google-tasks): return actual taskId in delete response

* fix(google-tasks): use absolute imports and fix registry order

* fix(google-tasks): rename list-task-lists to list_task_lists for doc generator

* improvement(google-tasks): destructure task and taskList outputs with typed schemas

* ran lint

* improvement(google-tasks): add wandConfig for due date timestamp generation
This commit is contained in:
Waleed
2026-02-25 21:52:34 -08:00
committed by GitHub
parent e4fb8b2fdd
commit 40016e79a1
20 changed files with 1386 additions and 0 deletions
+15
View File
@@ -1302,6 +1302,21 @@ export function GoogleCalendarIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function GoogleTasksIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 527.1 500' xmlns='http://www.w3.org/2000/svg'>
<polygon
fill='#0066DA'
points='410.4,58.3 368.8,81.2 348.2,120.6 368.8,168.8 407.8,211 450,187.5 475.9,142.8 450,87.5'
/>
<path
fill='#2684FC'
d='M249.3,219.4l98.9-98.9c29.1,22.1,50.5,53.8,59.6,90.4L272.1,346.7c-12.2,12.2-32,12.2-44.2,0l-91.5-91.5 c-9.8-9.8-9.8-25.6,0-35.3l39-39c9.8-9.8,25.6-9.8,35.3,0L249.3,219.4z M519.8,63.6l-39.7-39.7c-9.7-9.7-25.6-9.7-35.3,0 l-34.4,34.4c27.5,23,49.9,51.8,65.5,84.5l43.9-43.9C529.6,89.2,529.6,73.3,519.8,63.6z M412.5,250c0,89.8-72.8,162.5-162.5,162.5 S87.5,339.8,87.5,250S160.2,87.5,250,87.5c36.9,0,70.9,12.3,98.2,33.1l62.2-62.2C367,21.9,311.1,0,250,0C111.9,0,0,111.9,0,250 s111.9,250,250,250s250-111.9,250-250c0-38.3-8.7-74.7-24.1-107.2L407.8,211C410.8,223.5,412.5,236.6,412.5,250z'
/>
</svg>
)
}
export function SupabaseIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const gradient0 = `supabase_paint0_${id}`
+2
View File
@@ -53,6 +53,7 @@ import {
GoogleMapsIcon,
GoogleSheetsIcon,
GoogleSlidesIcon,
GoogleTasksIcon,
GoogleTranslateIcon,
GoogleVaultIcon,
GrafanaIcon,
@@ -200,6 +201,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
google_search: GoogleIcon,
google_sheets_v2: GoogleSheetsIcon,
google_slides_v2: GoogleSlidesIcon,
google_tasks: GoogleTasksIcon,
google_translate: GoogleTranslateIcon,
google_vault: GoogleVaultIcon,
grafana: GrafanaIcon,
@@ -0,0 +1,177 @@
---
title: Google Tasks
description: Manage Google Tasks
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="google_tasks"
color="#E0E0E0"
/>
## Usage Instructions
Integrate Google Tasks into your workflow. Create, read, update, delete, and list tasks and task lists.
## Tools
### `google_tasks_create`
Create a new task in a Google Tasks list
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `taskListId` | string | No | Task list ID \(defaults to primary task list "@default"\) |
| `title` | string | Yes | Title of the task \(max 1024 characters\) |
| `notes` | string | No | Notes/description for the task \(max 8192 characters\) |
| `due` | string | No | Due date in RFC 3339 format \(e.g., 2025-06-03T00:00:00.000Z\) |
| `status` | string | No | Task status: "needsAction" or "completed" |
| `parent` | string | No | Parent task ID to create this task as a subtask. Omit for top-level tasks. |
| `previous` | string | No | Previous sibling task ID to position after. Omit to place first among siblings. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Task ID |
| `title` | string | Task title |
| `notes` | string | Task notes |
| `status` | string | Task status \(needsAction or completed\) |
| `due` | string | Due date |
| `updated` | string | Last modification time |
| `selfLink` | string | URL for the task |
| `webViewLink` | string | Link to task in Google Tasks UI |
| `parent` | string | Parent task ID |
| `position` | string | Position among sibling tasks |
| `completed` | string | Completion date |
| `deleted` | boolean | Whether the task is deleted |
### `google_tasks_list`
List all tasks in a Google Tasks list
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `taskListId` | string | No | Task list ID \(defaults to primary task list "@default"\) |
| `maxResults` | number | No | Maximum number of tasks to return \(default 20, max 100\) |
| `pageToken` | string | No | Token for pagination |
| `showCompleted` | boolean | No | Whether to show completed tasks \(default true\) |
| `showDeleted` | boolean | No | Whether to show deleted tasks \(default false\) |
| `showHidden` | boolean | No | Whether to show hidden tasks \(default false\) |
| `dueMin` | string | No | Lower bound for due date filter \(RFC 3339 timestamp\) |
| `dueMax` | string | No | Upper bound for due date filter \(RFC 3339 timestamp\) |
| `completedMin` | string | No | Lower bound for task completion date \(RFC 3339 timestamp\) |
| `completedMax` | string | No | Upper bound for task completion date \(RFC 3339 timestamp\) |
| `updatedMin` | string | No | Lower bound for last modification time \(RFC 3339 timestamp\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tasks` | json | Array of tasks with id, title, notes, status, due, updated, and more |
| `nextPageToken` | string | Token for retrieving the next page of results |
### `google_tasks_get`
Retrieve a specific task by ID from a Google Tasks list
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `taskListId` | string | No | Task list ID \(defaults to primary task list "@default"\) |
| `taskId` | string | Yes | The ID of the task to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Task ID |
| `title` | string | Task title |
| `notes` | string | Task notes |
| `status` | string | Task status \(needsAction or completed\) |
| `due` | string | Due date |
| `updated` | string | Last modification time |
| `selfLink` | string | URL for the task |
| `webViewLink` | string | Link to task in Google Tasks UI |
| `parent` | string | Parent task ID |
| `position` | string | Position among sibling tasks |
| `completed` | string | Completion date |
| `deleted` | boolean | Whether the task is deleted |
### `google_tasks_update`
Update an existing task in a Google Tasks list
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `taskListId` | string | No | Task list ID \(defaults to primary task list "@default"\) |
| `taskId` | string | Yes | The ID of the task to update |
| `title` | string | No | New title for the task |
| `notes` | string | No | New notes for the task |
| `due` | string | No | New due date in RFC 3339 format |
| `status` | string | No | New status: "needsAction" or "completed" |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Task ID |
| `title` | string | Task title |
| `notes` | string | Task notes |
| `status` | string | Task status \(needsAction or completed\) |
| `due` | string | Due date |
| `updated` | string | Last modification time |
| `selfLink` | string | URL for the task |
| `webViewLink` | string | Link to task in Google Tasks UI |
| `parent` | string | Parent task ID |
| `position` | string | Position among sibling tasks |
| `completed` | string | Completion date |
| `deleted` | boolean | Whether the task is deleted |
### `google_tasks_delete`
Delete a task from a Google Tasks list
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `taskListId` | string | No | Task list ID \(defaults to primary task list "@default"\) |
| `taskId` | string | Yes | The ID of the task to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `taskId` | string | Deleted task ID |
| `deleted` | boolean | Whether deletion was successful |
### `google_tasks_list_task_lists`
Retrieve all task lists for the authenticated user
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `maxResults` | number | No | Maximum number of task lists to return \(default 1000, max 1000\) |
| `pageToken` | string | No | Token for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `taskLists` | json | Array of task lists with id, title, updated, and selfLink |
| `nextPageToken` | string | Token for retrieving the next page of results |
@@ -48,6 +48,7 @@
"google_search",
"google_sheets",
"google_slides",
"google_tasks",
"google_translate",
"google_vault",
"grafana",
@@ -40,6 +40,7 @@ const SCOPE_DESCRIPTIONS: Record<string, string> = {
'https://www.googleapis.com/auth/drive.file': 'View and manage Google Drive files',
'https://www.googleapis.com/auth/drive': 'Access all Google Drive files',
'https://www.googleapis.com/auth/calendar': 'View and manage calendar',
'https://www.googleapis.com/auth/tasks': 'Create, read, update, and delete Google Tasks',
'https://www.googleapis.com/auth/userinfo.email': 'View email address',
'https://www.googleapis.com/auth/userinfo.profile': 'View basic profile info',
'https://www.googleapis.com/auth/forms.body': 'View and manage Google Forms',
+262
View File
@@ -0,0 +1,262 @@
import { GoogleTasksIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import type { GoogleTasksResponse } from '@/tools/google_tasks/types'
export const GoogleTasksBlock: BlockConfig<GoogleTasksResponse> = {
type: 'google_tasks',
name: 'Google Tasks',
description: 'Manage Google Tasks',
longDescription:
'Integrate Google Tasks into your workflow. Create, read, update, delete, and list tasks and task lists.',
docsLink: 'https://docs.sim.ai/tools/google_tasks',
category: 'tools',
bgColor: '#E0E0E0',
icon: GoogleTasksIcon,
authMode: AuthMode.OAuth,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'Create Task', id: 'create' },
{ label: 'List Tasks', id: 'list' },
{ label: 'Get Task', id: 'get' },
{ label: 'Update Task', id: 'update' },
{ label: 'Delete Task', id: 'delete' },
{ label: 'List Task Lists', id: 'list_task_lists' },
],
value: () => 'create',
},
{
id: 'credential',
title: 'Google Tasks Account',
type: 'oauth-input',
canonicalParamId: 'oauthCredential',
mode: 'basic',
required: true,
serviceId: 'google-tasks',
requiredScopes: ['https://www.googleapis.com/auth/tasks'],
placeholder: 'Select Google Tasks account',
},
{
id: 'manualCredential',
title: 'Google Tasks Account',
type: 'short-input',
canonicalParamId: 'oauthCredential',
mode: 'advanced',
placeholder: 'Enter credential ID',
required: true,
},
// Task List ID - shown for all task operations (not list_task_lists)
{
id: 'taskListId',
title: 'Task List ID',
type: 'short-input',
placeholder: 'Task list ID (leave empty for default list)',
condition: { field: 'operation', value: 'list_task_lists', not: true },
},
// Create Task Fields
{
id: 'title',
title: 'Title',
type: 'short-input',
placeholder: 'Buy groceries',
condition: { field: 'operation', value: 'create' },
required: { field: 'operation', value: 'create' },
},
{
id: 'notes',
title: 'Notes',
type: 'long-input',
placeholder: 'Task notes or description',
condition: { field: 'operation', value: 'create' },
},
{
id: 'due',
title: 'Due Date',
type: 'short-input',
placeholder: '2025-06-03T00:00:00.000Z',
condition: { field: 'operation', value: 'create' },
wandConfig: {
enabled: true,
prompt: `Generate an RFC 3339 timestamp in UTC based on the user's description.
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SS.000Z (UTC timezone).
Examples:
- "tomorrow" -> Calculate tomorrow's date at 00:00:00.000Z
- "next Friday" -> Calculate the next Friday's date at 00:00:00.000Z
- "June 15" -> 2025-06-15T00:00:00.000Z
Return ONLY the timestamp - no explanations, no extra text.`,
},
},
{
id: 'status',
title: 'Status',
type: 'dropdown',
condition: { field: 'operation', value: 'create' },
options: [
{ label: 'Needs Action', id: 'needsAction' },
{ label: 'Completed', id: 'completed' },
],
},
// Get/Update/Delete Task Fields - Task ID
{
id: 'taskId',
title: 'Task ID',
type: 'short-input',
placeholder: 'Task ID',
condition: { field: 'operation', value: ['get', 'update', 'delete'] },
required: { field: 'operation', value: ['get', 'update', 'delete'] },
},
// Update Task Fields
{
id: 'title',
title: 'New Title',
type: 'short-input',
placeholder: 'Updated task title',
condition: { field: 'operation', value: 'update' },
},
{
id: 'notes',
title: 'New Notes',
type: 'long-input',
placeholder: 'Updated task notes',
condition: { field: 'operation', value: 'update' },
},
{
id: 'due',
title: 'New Due Date',
type: 'short-input',
placeholder: '2025-06-03T00:00:00.000Z',
condition: { field: 'operation', value: 'update' },
wandConfig: {
enabled: true,
prompt: `Generate an RFC 3339 timestamp in UTC based on the user's description.
The timestamp should be in the format: YYYY-MM-DDTHH:MM:SS.000Z (UTC timezone).
Examples:
- "tomorrow" -> Calculate tomorrow's date at 00:00:00.000Z
- "next Friday" -> Calculate the next Friday's date at 00:00:00.000Z
- "June 15" -> 2025-06-15T00:00:00.000Z
Return ONLY the timestamp - no explanations, no extra text.`,
},
},
{
id: 'status',
title: 'New Status',
type: 'dropdown',
condition: { field: 'operation', value: 'update' },
options: [
{ label: 'Needs Action', id: 'needsAction' },
{ label: 'Completed', id: 'completed' },
],
},
// List Tasks Fields
{
id: 'maxResults',
title: 'Max Results',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: ['list', 'list_task_lists'] },
},
{
id: 'showCompleted',
title: 'Show Completed',
type: 'dropdown',
condition: { field: 'operation', value: 'list' },
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
},
],
tools: {
access: [
'google_tasks_create',
'google_tasks_list',
'google_tasks_get',
'google_tasks_update',
'google_tasks_delete',
'google_tasks_list_task_lists',
],
config: {
tool: (params) => {
switch (params.operation) {
case 'create':
return 'google_tasks_create'
case 'list':
return 'google_tasks_list'
case 'get':
return 'google_tasks_get'
case 'update':
return 'google_tasks_update'
case 'delete':
return 'google_tasks_delete'
case 'list_task_lists':
return 'google_tasks_list_task_lists'
default:
throw new Error(`Invalid Google Tasks operation: ${params.operation}`)
}
},
params: (params) => {
const { oauthCredential, operation, showCompleted, maxResults, ...rest } = params
const processedParams: Record<string, unknown> = { ...rest }
if (maxResults && typeof maxResults === 'string') {
processedParams.maxResults = Number.parseInt(maxResults, 10)
}
if (showCompleted !== undefined) {
processedParams.showCompleted = showCompleted === 'true'
}
return {
oauthCredential,
...processedParams,
}
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
oauthCredential: { type: 'string', description: 'Google Tasks access token' },
taskListId: { type: 'string', description: 'Task list identifier' },
title: { type: 'string', description: 'Task title' },
notes: { type: 'string', description: 'Task notes' },
due: { type: 'string', description: 'Task due date' },
status: { type: 'string', description: 'Task status' },
taskId: { type: 'string', description: 'Task identifier' },
maxResults: { type: 'string', description: 'Maximum number of results' },
showCompleted: { type: 'string', description: 'Whether to show completed tasks' },
},
outputs: {
id: { type: 'string', description: 'Task ID' },
title: { type: 'string', description: 'Task title' },
notes: { type: 'string', description: 'Task notes' },
status: { type: 'string', description: 'Task status' },
due: { type: 'string', description: 'Due date' },
updated: { type: 'string', description: 'Last modification time' },
selfLink: { type: 'string', description: 'URL for the task' },
webViewLink: { type: 'string', description: 'Link to task in Google Tasks UI' },
parent: { type: 'string', description: 'Parent task ID' },
position: { type: 'string', description: 'Position among sibling tasks' },
completed: { type: 'string', description: 'Completion date' },
deleted: { type: 'boolean', description: 'Whether the task is deleted' },
tasks: { type: 'json', description: 'Array of tasks (list operation)' },
taskLists: { type: 'json', description: 'Array of task lists (list_task_lists operation)' },
taskId: { type: 'string', description: 'Deleted task ID (delete operation)' },
nextPageToken: { type: 'string', description: 'Token for next page of results' },
},
}
+2
View File
@@ -53,6 +53,7 @@ import { GoogleGroupsBlock } from '@/blocks/blocks/google_groups'
import { GoogleMapsBlock } from '@/blocks/blocks/google_maps'
import { GoogleSheetsBlock, GoogleSheetsV2Block } from '@/blocks/blocks/google_sheets'
import { GoogleSlidesBlock, GoogleSlidesV2Block } from '@/blocks/blocks/google_slides'
import { GoogleTasksBlock } from '@/blocks/blocks/google_tasks'
import { GoogleTranslateBlock } from '@/blocks/blocks/google_translate'
import { GoogleVaultBlock } from '@/blocks/blocks/google_vault'
import { GrafanaBlock } from '@/blocks/blocks/grafana'
@@ -236,6 +237,7 @@ export const registry: Record<string, BlockConfig> = {
google_forms: GoogleFormsBlock,
google_groups: GoogleGroupsBlock,
google_maps: GoogleMapsBlock,
google_tasks: GoogleTasksBlock,
google_translate: GoogleTranslateBlock,
gong: GongBlock,
google_search: GoogleSearchBlock,
+15
View File
@@ -1302,6 +1302,21 @@ export function GoogleCalendarIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function GoogleTasksIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 527.1 500' xmlns='http://www.w3.org/2000/svg'>
<polygon
fill='#0066DA'
points='410.4,58.3 368.8,81.2 348.2,120.6 368.8,168.8 407.8,211 450,187.5 475.9,142.8 450,87.5'
/>
<path
fill='#2684FC'
d='M249.3,219.4l98.9-98.9c29.1,22.1,50.5,53.8,59.6,90.4L272.1,346.7c-12.2,12.2-32,12.2-44.2,0l-91.5-91.5 c-9.8-9.8-9.8-25.6,0-35.3l39-39c9.8-9.8,25.6-9.8,35.3,0L249.3,219.4z M519.8,63.6l-39.7-39.7c-9.7-9.7-25.6-9.7-35.3,0 l-34.4,34.4c27.5,23,49.9,51.8,65.5,84.5l43.9-43.9C529.6,89.2,529.6,73.3,519.8,63.6z M412.5,250c0,89.8-72.8,162.5-162.5,162.5 S87.5,339.8,87.5,250S160.2,87.5,250,87.5c36.9,0,70.9,12.3,98.2,33.1l62.2-62.2C367,21.9,311.1,0,250,0C111.9,0,0,111.9,0,250 s111.9,250,250,250s250-111.9,250-250c0-38.3-8.7-74.7-24.1-107.2L407.8,211C410.8,223.5,412.5,236.6,412.5,250z'
/>
</svg>
)
}
export function SupabaseIcon(props: SVGProps<SVGSVGElement>) {
const id = useId()
const gradient0 = `supabase_paint0_${id}`
+41
View File
@@ -487,6 +487,7 @@ export const auth = betterAuth({
'google-bigquery',
'google-vault',
'google-groups',
'google-tasks',
'vertex-ai',
'github-repo',
'microsoft-dataverse',
@@ -1191,6 +1192,46 @@ export const auth = betterAuth({
},
},
{
providerId: 'google-tasks',
clientId: env.GOOGLE_CLIENT_ID as string,
clientSecret: env.GOOGLE_CLIENT_SECRET as string,
discoveryUrl: 'https://accounts.google.com/.well-known/openid-configuration',
accessType: 'offline',
scopes: [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/tasks',
],
prompt: 'consent',
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/google-tasks`,
getUserInfo: async (tokens) => {
try {
const response = await fetch('https://openidconnect.googleapis.com/v1/userinfo', {
headers: { Authorization: `Bearer ${tokens.accessToken}` },
})
if (!response.ok) {
logger.error('Failed to fetch Google user info', { status: response.status })
throw new Error(`Failed to fetch Google user info: ${response.statusText}`)
}
const profile = await response.json()
const now = new Date()
return {
id: `${profile.sub}-${crypto.randomUUID()}`,
name: profile.name || 'Google User',
email: profile.email,
image: profile.picture || undefined,
emailVerified: profile.email_verified || false,
createdAt: now,
updatedAt: now,
}
} catch (error) {
logger.error('Error in Google getUserInfo', { error })
throw error
}
},
},
{
providerId: 'vertex-ai',
clientId: env.GOOGLE_CLIENT_ID as string,
+9
View File
@@ -16,6 +16,7 @@ import {
GoogleGroupsIcon,
GoogleIcon,
GoogleSheetsIcon,
GoogleTasksIcon,
HubspotIcon,
JiraIcon,
LinearIcon,
@@ -128,6 +129,14 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
baseProviderIcon: GoogleIcon,
scopes: ['https://www.googleapis.com/auth/bigquery'],
},
'google-tasks': {
name: 'Google Tasks',
description: 'Create, manage, and organize tasks with Google Tasks.',
providerId: 'google-tasks',
icon: GoogleTasksIcon,
baseProviderIcon: GoogleIcon,
scopes: ['https://www.googleapis.com/auth/tasks'],
},
'google-vault': {
name: 'Google Vault',
description: 'Search, export, and manage matters/holds via Google Vault.',
+2
View File
@@ -8,6 +8,7 @@ export type OAuthProvider =
| 'google-sheets'
| 'google-calendar'
| 'google-bigquery'
| 'google-tasks'
| 'google-vault'
| 'google-forms'
| 'google-groups'
@@ -54,6 +55,7 @@ export type OAuthService =
| 'google-sheets'
| 'google-calendar'
| 'google-bigquery'
| 'google-tasks'
| 'google-vault'
| 'google-forms'
| 'google-groups'
+133
View File
@@ -0,0 +1,133 @@
import type { GoogleTasksCreateParams, GoogleTasksResponse } from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const createTool: ToolConfig<GoogleTasksCreateParams, GoogleTasksResponse> = {
id: 'google_tasks_create',
name: 'Google Tasks Create Task',
description: 'Create a new task in a Google Tasks list',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
taskListId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task list ID (defaults to primary task list "@default")',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Title of the task (max 1024 characters)',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Notes/description for the task (max 8192 characters)',
},
due: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date in RFC 3339 format (e.g., 2025-06-03T00:00:00.000Z)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task status: "needsAction" or "completed"',
},
parent: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Parent task ID to create this task as a subtask. Omit for top-level tasks.',
},
previous: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Previous sibling task ID to position after. Omit to place first among siblings.',
},
},
request: {
url: (params) => {
const taskListId = params.taskListId || '@default'
const queryParams = new URLSearchParams()
if (params.parent) queryParams.set('parent', params.parent)
if (params.previous) queryParams.set('previous', params.previous)
const qs = queryParams.toString()
return `${TASKS_API_BASE}/lists/${encodeURIComponent(taskListId)}/tasks${qs ? `?${qs}` : ''}`
},
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {
title: params.title,
}
if (params.notes) body.notes = params.notes
if (params.due) body.due = params.due
if (params.status) body.status = params.status
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message ?? 'Failed to create task')
}
return {
success: true,
output: {
id: data.id ?? null,
title: data.title ?? null,
notes: data.notes ?? null,
status: data.status ?? null,
due: data.due ?? null,
updated: data.updated ?? null,
selfLink: data.selfLink ?? null,
webViewLink: data.webViewLink ?? null,
parent: data.parent ?? null,
position: data.position ?? null,
completed: data.completed ?? null,
deleted: data.deleted ?? null,
},
}
},
outputs: {
id: { type: 'string', description: 'Task ID' },
title: { type: 'string', description: 'Task title' },
notes: { type: 'string', description: 'Task notes', optional: true },
status: { type: 'string', description: 'Task status (needsAction or completed)' },
due: { type: 'string', description: 'Due date', optional: true },
updated: { type: 'string', description: 'Last modification time' },
selfLink: { type: 'string', description: 'URL for the task' },
webViewLink: { type: 'string', description: 'Link to task in Google Tasks UI', optional: true },
parent: { type: 'string', description: 'Parent task ID', optional: true },
position: { type: 'string', description: 'Position among sibling tasks' },
completed: { type: 'string', description: 'Completion date', optional: true },
deleted: { type: 'boolean', description: 'Whether the task is deleted', optional: true },
},
}
+67
View File
@@ -0,0 +1,67 @@
import type { GoogleTasksDeleteParams, GoogleTasksDeleteResponse } from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const deleteTool: ToolConfig<GoogleTasksDeleteParams, GoogleTasksDeleteResponse> = {
id: 'google_tasks_delete',
name: 'Google Tasks Delete Task',
description: 'Delete a task from a Google Tasks list',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
taskListId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task list ID (defaults to primary task list "@default")',
},
taskId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the task to delete',
},
},
request: {
url: (params) => {
const taskListId = params.taskListId || '@default'
return `${TASKS_API_BASE}/lists/${encodeURIComponent(taskListId)}/tasks/${encodeURIComponent(params.taskId)}`
},
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response, params) => {
if (response.status === 204 || response.ok) {
return {
success: true,
output: {
taskId: params?.taskId || '',
deleted: true,
},
}
}
const data = await response.json()
throw new Error(data.error?.message ?? 'Failed to delete task')
},
outputs: {
taskId: { type: 'string', description: 'Deleted task ID' },
deleted: { type: 'boolean', description: 'Whether deletion was successful' },
},
}
+88
View File
@@ -0,0 +1,88 @@
import type { GoogleTasksGetParams, GoogleTasksResponse } from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const getTool: ToolConfig<GoogleTasksGetParams, GoogleTasksResponse> = {
id: 'google_tasks_get',
name: 'Google Tasks Get Task',
description: 'Retrieve a specific task by ID from a Google Tasks list',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
taskListId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task list ID (defaults to primary task list "@default")',
},
taskId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the task to retrieve',
},
},
request: {
url: (params) => {
const taskListId = params.taskListId || '@default'
return `${TASKS_API_BASE}/lists/${encodeURIComponent(taskListId)}/tasks/${encodeURIComponent(params.taskId)}`
},
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 task')
}
return {
success: true,
output: {
id: data.id ?? null,
title: data.title ?? null,
notes: data.notes ?? null,
status: data.status ?? null,
due: data.due ?? null,
updated: data.updated ?? null,
selfLink: data.selfLink ?? null,
webViewLink: data.webViewLink ?? null,
parent: data.parent ?? null,
position: data.position ?? null,
completed: data.completed ?? null,
deleted: data.deleted ?? null,
},
}
},
outputs: {
id: { type: 'string', description: 'Task ID' },
title: { type: 'string', description: 'Task title' },
notes: { type: 'string', description: 'Task notes', optional: true },
status: { type: 'string', description: 'Task status (needsAction or completed)' },
due: { type: 'string', description: 'Due date', optional: true },
updated: { type: 'string', description: 'Last modification time' },
selfLink: { type: 'string', description: 'URL for the task' },
webViewLink: { type: 'string', description: 'Link to task in Google Tasks UI', optional: true },
parent: { type: 'string', description: 'Parent task ID', optional: true },
position: { type: 'string', description: 'Position among sibling tasks' },
completed: { type: 'string', description: 'Completion date', optional: true },
deleted: { type: 'boolean', description: 'Whether the task is deleted', optional: true },
},
}
+6
View File
@@ -0,0 +1,6 @@
export { createTool as googleTasksCreateTool } from '@/tools/google_tasks/create'
export { deleteTool as googleTasksDeleteTool } from '@/tools/google_tasks/delete'
export { getTool as googleTasksGetTool } from '@/tools/google_tasks/get'
export { listTool as googleTasksListTool } from '@/tools/google_tasks/list'
export { listTaskListsTool as googleTasksListTaskListsTool } from '@/tools/google_tasks/list_task_lists'
export { updateTool as googleTasksUpdateTool } from '@/tools/google_tasks/update'
+214
View File
@@ -0,0 +1,214 @@
import type { GoogleTasksListParams, GoogleTasksListResponse } from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const listTool: ToolConfig<GoogleTasksListParams, GoogleTasksListResponse> = {
id: 'google_tasks_list',
name: 'Google Tasks List Tasks',
description: 'List all tasks in a Google Tasks list',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
taskListId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task list ID (defaults to primary task list "@default")',
},
maxResults: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of tasks to return (default 20, max 100)',
},
pageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination',
},
showCompleted: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to show completed tasks (default true)',
},
showDeleted: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to show deleted tasks (default false)',
},
showHidden: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to show hidden tasks (default false)',
},
dueMin: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Lower bound for due date filter (RFC 3339 timestamp)',
},
dueMax: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Upper bound for due date filter (RFC 3339 timestamp)',
},
completedMin: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Lower bound for task completion date (RFC 3339 timestamp)',
},
completedMax: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Upper bound for task completion date (RFC 3339 timestamp)',
},
updatedMin: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Lower bound for last modification time (RFC 3339 timestamp)',
},
},
request: {
url: (params) => {
const taskListId = params.taskListId || '@default'
const queryParams = new URLSearchParams()
if (params.maxResults) queryParams.set('maxResults', String(params.maxResults))
if (params.pageToken) queryParams.set('pageToken', params.pageToken)
if (params.showCompleted !== undefined)
queryParams.set('showCompleted', String(params.showCompleted))
if (params.showDeleted !== undefined)
queryParams.set('showDeleted', String(params.showDeleted))
if (params.showHidden !== undefined) queryParams.set('showHidden', String(params.showHidden))
if (params.dueMin) queryParams.set('dueMin', params.dueMin)
if (params.dueMax) queryParams.set('dueMax', params.dueMax)
if (params.completedMin) queryParams.set('completedMin', params.completedMin)
if (params.completedMax) queryParams.set('completedMax', params.completedMax)
if (params.updatedMin) queryParams.set('updatedMin', params.updatedMin)
const qs = queryParams.toString()
return `${TASKS_API_BASE}/lists/${encodeURIComponent(taskListId)}/tasks${qs ? `?${qs}` : ''}`
},
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 tasks')
}
const items = data.items ?? []
return {
success: true,
output: {
tasks: items.map((item: Record<string, unknown>) => ({
id: (item.id as string) ?? null,
title: (item.title as string) ?? null,
notes: (item.notes as string) ?? null,
status: (item.status as string) ?? null,
due: (item.due as string) ?? null,
completed: (item.completed as string) ?? null,
updated: (item.updated as string) ?? null,
selfLink: (item.selfLink as string) ?? null,
webViewLink: (item.webViewLink as string) ?? null,
parent: (item.parent as string) ?? null,
position: (item.position as string) ?? null,
hidden: (item.hidden as boolean) ?? null,
deleted: (item.deleted as boolean) ?? null,
links: Array.isArray(item.links)
? (item.links as Array<Record<string, string>>).map((link) => ({
type: link.type ?? '',
description: link.description ?? '',
link: link.link ?? '',
}))
: [],
})),
nextPageToken: data.nextPageToken ?? null,
},
}
},
outputs: {
tasks: {
type: 'array',
description: 'List of tasks',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Task identifier' },
title: { type: 'string', description: 'Title of the task' },
notes: { type: 'string', description: 'Notes/description for the task', optional: true },
status: {
type: 'string',
description: 'Task status: "needsAction" or "completed"',
},
due: { type: 'string', description: 'Due date (RFC 3339 timestamp)', optional: true },
completed: {
type: 'string',
description: 'Completion date (RFC 3339 timestamp)',
optional: true,
},
updated: { type: 'string', description: 'Last modification time (RFC 3339 timestamp)' },
selfLink: { type: 'string', description: 'URL pointing to this task' },
webViewLink: {
type: 'string',
description: 'Link to task in Google Tasks UI',
optional: true,
},
parent: { type: 'string', description: 'Parent task identifier', optional: true },
position: {
type: 'string',
description: 'Position among sibling tasks (string-based ordering)',
},
hidden: { type: 'boolean', description: 'Whether the task is hidden', optional: true },
deleted: { type: 'boolean', description: 'Whether the task is deleted', optional: true },
links: {
type: 'array',
description: 'Collection of links associated with the task',
optional: true,
items: {
type: 'object',
properties: {
type: {
type: 'string',
description: 'Link type (e.g., "email", "generic", "chat_message")',
},
description: { type: 'string', description: 'Link description' },
link: { type: 'string', description: 'The URL' },
},
},
},
},
},
},
nextPageToken: {
type: 'string',
description: 'Token for retrieving the next page of results',
optional: true,
},
},
}
@@ -0,0 +1,103 @@
import type {
GoogleTasksListTaskListsParams,
GoogleTasksListTaskListsResponse,
} from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const listTaskListsTool: ToolConfig<
GoogleTasksListTaskListsParams,
GoogleTasksListTaskListsResponse
> = {
id: 'google_tasks_list_task_lists',
name: 'Google Tasks List Task Lists',
description: 'Retrieve all task lists for the authenticated user',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
maxResults: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of task lists to return (default 20, max 100)',
},
pageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.maxResults) queryParams.set('maxResults', String(params.maxResults))
if (params.pageToken) queryParams.set('pageToken', params.pageToken)
const qs = queryParams.toString()
return `${TASKS_API_BASE}/users/@me/lists${qs ? `?${qs}` : ''}`
},
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 task lists')
}
const items = data.items ?? []
return {
success: true,
output: {
taskLists: items.map((item: Record<string, unknown>) => ({
id: (item.id as string) ?? null,
title: (item.title as string) ?? null,
updated: (item.updated as string) ?? null,
selfLink: (item.selfLink as string) ?? null,
})),
nextPageToken: data.nextPageToken ?? null,
},
}
},
outputs: {
taskLists: {
type: 'array',
description: 'List of task lists',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Task list identifier' },
title: { type: 'string', description: 'Title of the task list' },
updated: {
type: 'string',
description: 'Last modification time (RFC 3339 timestamp)',
},
selfLink: { type: 'string', description: 'URL pointing to this task list' },
},
},
},
nextPageToken: {
type: 'string',
description: 'Token for retrieving the next page of results',
optional: true,
},
},
}
+113
View File
@@ -0,0 +1,113 @@
import type { ToolResponse } from '@/tools/types'
export const TASKS_API_BASE = 'https://tasks.googleapis.com/tasks/v1'
export interface BaseGoogleTasksParams {
accessToken: string
}
export interface GoogleTasksListTaskListsParams extends BaseGoogleTasksParams {
maxResults?: number
pageToken?: string
}
export interface GoogleTasksCreateParams extends BaseGoogleTasksParams {
taskListId?: string
title: string
notes?: string
due?: string
status?: string
parent?: string
previous?: string
}
export interface GoogleTasksListParams extends BaseGoogleTasksParams {
taskListId?: string
maxResults?: number
pageToken?: string
showCompleted?: boolean
showDeleted?: boolean
showHidden?: boolean
dueMin?: string
dueMax?: string
completedMin?: string
completedMax?: string
updatedMin?: string
}
export interface GoogleTasksGetParams extends BaseGoogleTasksParams {
taskListId?: string
taskId: string
}
export interface GoogleTasksUpdateParams extends BaseGoogleTasksParams {
taskListId?: string
taskId: string
title?: string
notes?: string
due?: string
status?: string
}
export interface GoogleTasksDeleteParams extends BaseGoogleTasksParams {
taskListId?: string
taskId: string
}
export interface GoogleTasksResponse extends ToolResponse {
output: {
id: string | null
title: string | null
notes: string | null
status: string | null
due: string | null
updated: string | null
selfLink: string | null
webViewLink: string | null
parent: string | null
position: string | null
completed: string | null
deleted: boolean | null
}
}
export interface GoogleTasksListResponse extends ToolResponse {
output: {
tasks: Array<{
id: string | null
title: string | null
notes: string | null
status: string | null
due: string | null
completed: string | null
updated: string | null
selfLink: string | null
webViewLink: string | null
parent: string | null
position: string | null
hidden: boolean | null
deleted: boolean | null
links: Array<{ type: string; description: string; link: string }>
}>
nextPageToken: string | null
}
}
export interface GoogleTasksListTaskListsResponse extends ToolResponse {
output: {
taskLists: Array<{
id: string | null
title: string | null
updated: string | null
selfLink: string | null
}>
nextPageToken: string | null
}
}
export interface GoogleTasksDeleteResponse extends ToolResponse {
output: {
taskId: string
deleted: boolean
}
}
+121
View File
@@ -0,0 +1,121 @@
import type { GoogleTasksResponse, GoogleTasksUpdateParams } from '@/tools/google_tasks/types'
import { TASKS_API_BASE } from '@/tools/google_tasks/types'
import type { ToolConfig } from '@/tools/types'
export const updateTool: ToolConfig<GoogleTasksUpdateParams, GoogleTasksResponse> = {
id: 'google_tasks_update',
name: 'Google Tasks Update Task',
description: 'Update an existing task in a Google Tasks list',
version: '1.0.0',
oauth: {
required: true,
provider: 'google-tasks',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Google Tasks OAuth access token',
},
taskListId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Task list ID (defaults to primary task list "@default")',
},
taskId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the task to update',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New title for the task',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New notes for the task',
},
due: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New due date in RFC 3339 format',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New status: "needsAction" or "completed"',
},
},
request: {
url: (params) => {
const taskListId = params.taskListId || '@default'
return `${TASKS_API_BASE}/lists/${encodeURIComponent(taskListId)}/tasks/${encodeURIComponent(params.taskId)}`
},
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {}
if (params.title !== undefined) body.title = params.title
if (params.notes !== undefined) body.notes = params.notes
if (params.due !== undefined) body.due = params.due
if (params.status !== undefined) body.status = params.status
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error?.message ?? 'Failed to update task')
}
return {
success: true,
output: {
id: data.id ?? null,
title: data.title ?? null,
notes: data.notes ?? null,
status: data.status ?? null,
due: data.due ?? null,
updated: data.updated ?? null,
selfLink: data.selfLink ?? null,
webViewLink: data.webViewLink ?? null,
parent: data.parent ?? null,
position: data.position ?? null,
completed: data.completed ?? null,
deleted: data.deleted ?? null,
},
}
},
outputs: {
id: { type: 'string', description: 'Task ID' },
title: { type: 'string', description: 'Task title' },
notes: { type: 'string', description: 'Task notes', optional: true },
status: { type: 'string', description: 'Task status (needsAction or completed)' },
due: { type: 'string', description: 'Due date', optional: true },
updated: { type: 'string', description: 'Last modification time' },
selfLink: { type: 'string', description: 'URL for the task' },
webViewLink: { type: 'string', description: 'Link to task in Google Tasks UI', optional: true },
parent: { type: 'string', description: 'Parent task ID', optional: true },
position: { type: 'string', description: 'Position among sibling tasks' },
completed: { type: 'string', description: 'Completion date', optional: true },
deleted: { type: 'boolean', description: 'Whether the task is deleted', optional: true },
},
}
+14
View File
@@ -776,6 +776,14 @@ import {
googleSlidesUpdateSlidesPositionTool,
googleSlidesWriteTool,
} from '@/tools/google_slides'
import {
googleTasksCreateTool,
googleTasksDeleteTool,
googleTasksGetTool,
googleTasksListTaskListsTool,
googleTasksListTool,
googleTasksUpdateTool,
} from '@/tools/google_tasks'
import { googleTranslateDetectTool, googleTranslateTool } from '@/tools/google_translate'
import {
createMattersExportTool,
@@ -2942,6 +2950,12 @@ export const tools: Record<string, ToolConfig> = {
google_maps_speed_limits: googleMapsSpeedLimitsTool,
google_maps_timezone: googleMapsTimezoneTool,
google_maps_validate_address: googleMapsValidateAddressTool,
google_tasks_create: googleTasksCreateTool,
google_tasks_delete: googleTasksDeleteTool,
google_tasks_get: googleTasksGetTool,
google_tasks_list: googleTasksListTool,
google_tasks_list_task_lists: googleTasksListTaskListsTool,
google_tasks_update: googleTasksUpdateTool,
google_translate_detect: googleTranslateDetectTool,
google_translate_text: googleTranslateTool,
google_sheets_read: googleSheetsReadTool,