mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 23:17:59 -05:00
Added notion tool/block
This commit is contained in:
69
blocks/blocks/notion.ts
Normal file
69
blocks/blocks/notion.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { NotionIcon } from '@/components/icons'
|
||||
import { NotionResponse } from '@/tools/notion/read'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
export const NotionBlock: BlockConfig<NotionResponse> = {
|
||||
type: 'notion_reader',
|
||||
toolbar: {
|
||||
title: 'Notion',
|
||||
description: 'Read and write to Notion pages and databases',
|
||||
bgColor: '#000000',
|
||||
icon: NotionIcon,
|
||||
category: 'tools',
|
||||
},
|
||||
tools: {
|
||||
access: ['notion_read', 'notion_write'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
return params.operation === 'write' ? 'notion_write' : 'notion_read'
|
||||
},
|
||||
},
|
||||
},
|
||||
workflow: {
|
||||
inputs: {
|
||||
pageId: { type: 'string', required: true },
|
||||
operation: { type: 'string', required: true },
|
||||
content: { type: 'string', required: false },
|
||||
apiKey: { type: 'string', required: true },
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
content: 'string',
|
||||
metadata: 'any',
|
||||
},
|
||||
},
|
||||
},
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: ['read', 'write'],
|
||||
},
|
||||
{
|
||||
id: 'pageId',
|
||||
title: 'Page ID',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter Notion page ID',
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: 'Content',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter content to write (for write operation)',
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter your Notion API key',
|
||||
password: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { FirecrawlScrapeBlock } from './blocks/firecrawl'
|
||||
import { FunctionBlock } from './blocks/function'
|
||||
import { GitHubBlock } from './blocks/github'
|
||||
import { JinaBlock } from './blocks/jina'
|
||||
import { NotionBlock } from './blocks/notion'
|
||||
import { RouterBlock } from './blocks/router'
|
||||
import { SerperBlock } from './blocks/serper'
|
||||
import { SlackMessageBlock } from './blocks/slack'
|
||||
@@ -32,6 +33,7 @@ export {
|
||||
TavilyExtractBlock,
|
||||
RouterBlock,
|
||||
YouTubeSearchBlock,
|
||||
NotionBlock,
|
||||
}
|
||||
|
||||
// Registry of all block configurations
|
||||
@@ -51,6 +53,7 @@ const blocks: Record<string, BlockConfig> = {
|
||||
tavily_search: TavilySearchBlock,
|
||||
tavily_extract: TavilyExtractBlock,
|
||||
youtube_search: YouTubeSearchBlock,
|
||||
notion_reader: NotionBlock,
|
||||
}
|
||||
|
||||
// Build a reverse mapping of tools to block types
|
||||
|
||||
@@ -9,6 +9,8 @@ import { chatTool as googleChat } from './google/chat'
|
||||
import { requestTool as httpRequest } from './http/request'
|
||||
import { contactsTool as hubspotContacts } from './hubspot/contacts'
|
||||
import { readUrlTool } from './jina/reader'
|
||||
import { notionReadTool } from './notion/read'
|
||||
import { notionWriteTool } from './notion/write'
|
||||
import { chatTool as openAIChat } from './openai/chat'
|
||||
import { opportunitiesTool as salesforceOpportunities } from './salesforce/opportunities'
|
||||
import { searchTool as serperSearch } from './serper/search'
|
||||
@@ -21,35 +23,27 @@ import { youtubeSearchTool } from './youtube/search'
|
||||
|
||||
// Registry of all available tools
|
||||
export const tools: Record<string, ToolConfig> = {
|
||||
// AI Models
|
||||
openai_chat: openAIChat,
|
||||
anthropic_chat: anthropicChat,
|
||||
google_chat: googleChat,
|
||||
xai_chat: xaiChat,
|
||||
deepseek_chat: deepseekChat,
|
||||
deepseek_reasoner: deepseekReasoner,
|
||||
// HTTP
|
||||
http_request: httpRequest,
|
||||
// CRM Tools
|
||||
hubspot_contacts: hubspotContacts,
|
||||
salesforce_opportunities: salesforceOpportunities,
|
||||
// Function Tools
|
||||
function_execute: functionExecute,
|
||||
// CrewAI Tools
|
||||
crewai_vision: crewAIVision,
|
||||
// Firecrawl Tools
|
||||
firecrawl_scrape: scrapeTool,
|
||||
// Jina Tools
|
||||
jina_readurl: readUrlTool,
|
||||
// Slack Tools
|
||||
slack_message: slackMessageTool,
|
||||
// GitHub Tools
|
||||
github_repoinfo: repoInfoTool,
|
||||
// Search Tools
|
||||
serper_search: serperSearch,
|
||||
tavily_search: tavilySearch,
|
||||
tavily_extract: tavilyExtract,
|
||||
youtube_search: youtubeSearchTool,
|
||||
notion_read: notionReadTool,
|
||||
notion_write: notionWriteTool,
|
||||
}
|
||||
|
||||
// Get a tool by its ID
|
||||
|
||||
85
tools/notion/read.ts
Normal file
85
tools/notion/read.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { ToolConfig, ToolResponse } from '../types'
|
||||
|
||||
export interface NotionReadParams {
|
||||
pageId: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface NotionResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
metadata?: {
|
||||
title?: string
|
||||
lastEditedTime?: string
|
||||
createdTime?: string
|
||||
url?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const notionReadTool: ToolConfig<NotionReadParams, NotionResponse> = {
|
||||
id: 'notion_read',
|
||||
name: 'Notion Reader',
|
||||
description: 'Read content from a Notion page',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
pageId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'The ID of the Notion page to read',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Your Notion API key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: NotionReadParams) => {
|
||||
// Format page ID with hyphens if needed
|
||||
const formattedId = params.pageId.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
|
||||
return `https://api.notion.com/v1/blocks/${formattedId}/children?page_size=100`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: NotionReadParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Notion-Version': '2022-06-28',
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
// Extract text content from blocks
|
||||
const blocks = data.results || []
|
||||
const content = blocks
|
||||
.map((block: any) => {
|
||||
if (block.type === 'paragraph') {
|
||||
return block.paragraph.rich_text.map((text: any) => text.plain_text).join('')
|
||||
}
|
||||
return ''
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n\n')
|
||||
|
||||
return {
|
||||
success: response.ok,
|
||||
output: {
|
||||
content: content,
|
||||
metadata: {
|
||||
lastEditedTime: blocks[0]?.last_edited_time,
|
||||
createdTime: blocks[0]?.created_time,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'Failed to read Notion page'
|
||||
},
|
||||
}
|
||||
81
tools/notion/write.ts
Normal file
81
tools/notion/write.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { NotionResponse } from './read'
|
||||
|
||||
export interface NotionWriteParams {
|
||||
pageId: string
|
||||
content: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export const notionWriteTool: ToolConfig<NotionWriteParams, NotionResponse> = {
|
||||
id: 'notion_write',
|
||||
name: 'Notion Writer',
|
||||
description: 'Write content to a Notion page',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
pageId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'The ID of the Notion page to write to',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The content to write to the page',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Your Notion API key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: NotionWriteParams) => {
|
||||
// Format page ID with hyphens if needed
|
||||
const formattedId = params.pageId.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5')
|
||||
return `https://api.notion.com/v1/blocks/${formattedId}/children`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params: NotionWriteParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Notion-Version': '2022-06-28',
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params: NotionWriteParams) => ({
|
||||
children: [
|
||||
{
|
||||
object: 'block',
|
||||
type: 'paragraph',
|
||||
paragraph: {
|
||||
rich_text: [
|
||||
{
|
||||
type: 'text',
|
||||
text: {
|
||||
content: params.content,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: response.ok,
|
||||
output: {
|
||||
content: 'Successfully appended content to Notion page',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'Failed to write to Notion page'
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user