mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(reddit): better error logging
This commit is contained in:
@@ -84,7 +84,7 @@ export const RedditBlock: BlockConfig<
|
||||
},
|
||||
{
|
||||
id: 'limit',
|
||||
title: 'Number of Posts',
|
||||
title: 'Max Posts',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
|
||||
@@ -40,73 +40,124 @@ export const getCommentsTool: ToolConfig<RedditCommentsParams, RedditCommentsRes
|
||||
const limit = Math.min(Math.max(1, params.limit || 50), 100)
|
||||
|
||||
// Build URL
|
||||
return `https://www.reddit.com/r/${subreddit}/comments/${params.postId}.json?sort=${sort}&limit=${limit}`
|
||||
return `https://www.reddit.com/r/${subreddit}/comments/${params.postId}.json?sort=${sort}&limit=${limit}&raw_json=1`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'Sim Studio Reddit Tool/1.0',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
transformResponse: async (response: Response, requestParams?: RedditCommentsParams) => {
|
||||
try {
|
||||
// Check if response is OK
|
||||
if (!response.ok) {
|
||||
if (response.status === 403 || response.status === 429) {
|
||||
throw new Error('Reddit API access blocked or rate limited. Please try again later.')
|
||||
}
|
||||
throw new Error(`Reddit API returned ${response.status}: ${response.statusText}`)
|
||||
}
|
||||
|
||||
// Extract post data (first element in the array)
|
||||
const postData = data[0]?.data?.children[0]?.data || {}
|
||||
// Attempt to parse JSON
|
||||
let data
|
||||
try {
|
||||
data = await response.json()
|
||||
} catch (error) {
|
||||
throw new Error('Failed to parse Reddit API response: Response was not valid JSON')
|
||||
}
|
||||
|
||||
// Extract and transform comments (second element in the array)
|
||||
const commentsData = data[1]?.data?.children || []
|
||||
// Validate data structure
|
||||
if (!Array.isArray(data) || data.length < 2) {
|
||||
throw new Error('Invalid response format from Reddit API')
|
||||
}
|
||||
|
||||
// Recursive function to process nested comments
|
||||
const processComments = (comments: any[]): any[] => {
|
||||
return comments
|
||||
.map((comment) => {
|
||||
const commentData = comment.data
|
||||
// Extract post data (first element in the array)
|
||||
const postData = data[0]?.data?.children[0]?.data || {}
|
||||
|
||||
// Skip non-comment items like "more" items
|
||||
if (!commentData || comment.kind !== 't1') {
|
||||
return null
|
||||
}
|
||||
// Extract and transform comments (second element in the array)
|
||||
const commentsData = data[1]?.data?.children || []
|
||||
|
||||
// Process nested replies if they exist
|
||||
const replies =
|
||||
commentData.replies && commentData.replies.data && commentData.replies.data.children
|
||||
? processComments(commentData.replies.data.children)
|
||||
: []
|
||||
// Recursive function to process nested comments
|
||||
const processComments = (comments: any[]): any[] => {
|
||||
return comments
|
||||
.map((comment) => {
|
||||
const commentData = comment.data
|
||||
|
||||
return {
|
||||
id: commentData.id,
|
||||
author: commentData.author,
|
||||
body: commentData.body,
|
||||
created_utc: commentData.created_utc,
|
||||
score: commentData.score,
|
||||
permalink: `https://www.reddit.com${commentData.permalink}`,
|
||||
replies: replies.filter(Boolean),
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
// Skip non-comment items like "more" items
|
||||
if (!commentData || comment.kind !== 't1') {
|
||||
return null
|
||||
}
|
||||
|
||||
const comments = processComments(commentsData)
|
||||
// Process nested replies if they exist
|
||||
const replies =
|
||||
commentData.replies && commentData.replies.data && commentData.replies.data.children
|
||||
? processComments(commentData.replies.data.children)
|
||||
: []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
post: {
|
||||
id: postData.id,
|
||||
title: postData.title,
|
||||
author: postData.author,
|
||||
selftext: postData.selftext,
|
||||
created_utc: postData.created_utc,
|
||||
score: postData.score,
|
||||
permalink: `https://www.reddit.com${postData.permalink}`,
|
||||
return {
|
||||
id: commentData.id || '',
|
||||
author: commentData.author || '[deleted]',
|
||||
body: commentData.body || '',
|
||||
created_utc: commentData.created_utc || 0,
|
||||
score: commentData.score || 0,
|
||||
permalink: commentData.permalink ? `https://www.reddit.com${commentData.permalink}` : '',
|
||||
replies: replies.filter(Boolean),
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
const comments = processComments(commentsData)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
post: {
|
||||
id: postData.id || '',
|
||||
title: postData.title || '',
|
||||
author: postData.author || '[deleted]',
|
||||
selftext: postData.selftext || '',
|
||||
created_utc: postData.created_utc || 0,
|
||||
score: postData.score || 0,
|
||||
permalink: postData.permalink ? `https://www.reddit.com${postData.permalink}` : '',
|
||||
},
|
||||
comments: comments,
|
||||
},
|
||||
comments: comments,
|
||||
},
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || 'Unknown error'
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
post: {
|
||||
id: '',
|
||||
title: '',
|
||||
author: '',
|
||||
selftext: '',
|
||||
created_utc: 0,
|
||||
score: 0,
|
||||
permalink: '',
|
||||
},
|
||||
comments: [],
|
||||
},
|
||||
error: errorMessage
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return `Error fetching Reddit comments: ${error.message}`
|
||||
transformError: (error): string => {
|
||||
// Create detailed error message
|
||||
let errorMessage = error.message || 'Unknown error'
|
||||
|
||||
if (errorMessage.includes('blocked') || errorMessage.includes('rate limited')) {
|
||||
errorMessage = `Reddit access is currently unavailable: ${errorMessage}. Consider reducing request frequency or using the official Reddit API with authentication.`
|
||||
}
|
||||
|
||||
if (errorMessage.includes('not valid JSON')) {
|
||||
errorMessage = 'Unable to process Reddit response: Received non-JSON response, which typically happens when Reddit blocks automated access.'
|
||||
}
|
||||
|
||||
return `Error fetching Reddit comments: ${errorMessage}`
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export const getPostsTool: ToolConfig<RedditPostsParams, RedditPostsResponse> =
|
||||
const limit = Math.min(Math.max(1, params.limit || 10), 100)
|
||||
|
||||
// Build URL with appropriate parameters
|
||||
let url = `https://www.reddit.com/r/${subreddit}/${sort}.json?limit=${limit}`
|
||||
let url = `https://www.reddit.com/r/${subreddit}/${sort}.json?limit=${limit}&raw_json=1`
|
||||
|
||||
// Add time parameter only for 'top' sorting
|
||||
if (sort === 'top' && params.time) {
|
||||
@@ -51,46 +51,88 @@ export const getPostsTool: ToolConfig<RedditPostsParams, RedditPostsResponse> =
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'Sim Studio Reddit Tool/1.0',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
transformResponse: async (response: Response, requestParams?: RedditPostsParams) => {
|
||||
try {
|
||||
// Check if response is OK
|
||||
if (!response.ok) {
|
||||
if (response.status === 403 || response.status === 429) {
|
||||
throw new Error('Reddit API access blocked or rate limited. Please try again later.')
|
||||
}
|
||||
throw new Error(`Reddit API returned ${response.status}: ${response.statusText}`)
|
||||
}
|
||||
|
||||
// Extract subreddit name from response
|
||||
const subredditName = data.data?.children[0]?.data?.subreddit || 'unknown'
|
||||
// Attempt to parse JSON
|
||||
let data
|
||||
try {
|
||||
data = await response.json()
|
||||
} catch (error) {
|
||||
throw new Error('Failed to parse Reddit API response: Response was not valid JSON')
|
||||
}
|
||||
|
||||
// Transform posts data
|
||||
const posts =
|
||||
data.data?.children.map((child: any) => {
|
||||
const post = child.data
|
||||
// Check if response contains error
|
||||
if (data.error || !data.data) {
|
||||
throw new Error(data.message || 'Invalid response from Reddit API')
|
||||
}
|
||||
|
||||
// Extract subreddit name from response (with fallback)
|
||||
const subredditName = data.data?.children[0]?.data?.subreddit || requestParams?.subreddit || 'unknown'
|
||||
|
||||
// Transform posts data with proper error handling
|
||||
const posts = data.data?.children?.map((child: any) => {
|
||||
const post = child.data || {}
|
||||
return {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
author: post.author,
|
||||
url: post.url,
|
||||
permalink: `https://www.reddit.com${post.permalink}`,
|
||||
created_utc: post.created_utc,
|
||||
score: post.score,
|
||||
num_comments: post.num_comments,
|
||||
is_self: post.is_self,
|
||||
selftext: post.selftext,
|
||||
thumbnail: post.thumbnail,
|
||||
subreddit: post.subreddit,
|
||||
id: post.id || '',
|
||||
title: post.title || '',
|
||||
author: post.author || '[deleted]',
|
||||
url: post.url || '',
|
||||
permalink: post.permalink ? `https://www.reddit.com${post.permalink}` : '',
|
||||
created_utc: post.created_utc || 0,
|
||||
score: post.score || 0,
|
||||
num_comments: post.num_comments || 0,
|
||||
is_self: !!post.is_self,
|
||||
selftext: post.selftext || '',
|
||||
thumbnail: post.thumbnail || '',
|
||||
subreddit: post.subreddit || subredditName,
|
||||
}
|
||||
}) || []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
subreddit: subredditName,
|
||||
posts,
|
||||
},
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
subreddit: subredditName,
|
||||
posts,
|
||||
},
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || 'Unknown error'
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
subreddit: requestParams?.subreddit || 'unknown',
|
||||
posts: [],
|
||||
},
|
||||
error: errorMessage
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return `Error fetching Reddit posts: ${error.message}`
|
||||
transformError: (error): string => {
|
||||
// Create detailed error message
|
||||
let errorMessage = error.message || 'Unknown error'
|
||||
|
||||
if (errorMessage.includes('blocked') || errorMessage.includes('rate limited')) {
|
||||
errorMessage = `Reddit access is currently unavailable: ${errorMessage}. Consider reducing request frequency or using the official Reddit API with authentication.`
|
||||
}
|
||||
|
||||
if (errorMessage.includes('not valid JSON')) {
|
||||
errorMessage = 'Unable to process Reddit response: Received non-JSON response, which typically happens when Reddit blocks automated access.'
|
||||
}
|
||||
|
||||
return `Error fetching Reddit posts: ${errorMessage}`
|
||||
},
|
||||
}
|
||||
|
||||
@@ -26,60 +26,101 @@ export const hotPostsTool: ToolConfig<HotPostsParams, RedditHotPostsResponse> =
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://www.reddit.com/r/${params.subreddit}/hot.json?limit=${params.limit || 10}`,
|
||||
url: (params) => {
|
||||
// Sanitize inputs and enforce limits
|
||||
const subreddit = params.subreddit.trim().replace(/^r\//, '')
|
||||
const limit = Math.min(Math.max(1, params.limit || 10), 100)
|
||||
|
||||
return `https://www.reddit.com/r/${subreddit}/hot.json?limit=${limit}&raw_json=1`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0.0',
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
|
||||
'Accept': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to fetch Reddit posts')
|
||||
}
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.message || 'Reddit API error')
|
||||
}
|
||||
|
||||
const posts: RedditPost[] = data.data.children.map((child: any) => {
|
||||
const post = child.data
|
||||
return {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
author: post.author,
|
||||
url: post.url,
|
||||
permalink: `https://www.reddit.com${post.permalink}`,
|
||||
created_utc: post.created_utc,
|
||||
score: post.score,
|
||||
num_comments: post.num_comments,
|
||||
selftext: post.selftext,
|
||||
thumbnail:
|
||||
post.thumbnail !== 'self' && post.thumbnail !== 'default' ? post.thumbnail : undefined,
|
||||
is_self: post.is_self,
|
||||
subreddit: post.subreddit,
|
||||
subreddit_name_prefixed: post.subreddit_name_prefixed,
|
||||
transformResponse: async (response: Response, requestParams?: HotPostsParams) => {
|
||||
try {
|
||||
// Check if response is OK
|
||||
if (!response.ok) {
|
||||
if (response.status === 403 || response.status === 429) {
|
||||
throw new Error('Reddit API access blocked or rate limited. Please try again later.')
|
||||
}
|
||||
throw new Error(`Reddit API returned ${response.status}: ${response.statusText}`)
|
||||
}
|
||||
})
|
||||
|
||||
// Extract the subreddit name from the response data
|
||||
const subreddit =
|
||||
data.data?.children?.[0]?.data?.subreddit || (posts.length > 0 ? posts[0].subreddit : '')
|
||||
// Attempt to parse JSON
|
||||
let data
|
||||
try {
|
||||
data = await response.json()
|
||||
} catch (error) {
|
||||
throw new Error('Failed to parse Reddit API response: Response was not valid JSON')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
subreddit,
|
||||
posts,
|
||||
},
|
||||
// Check if response contains error
|
||||
if (data.error || !data.data) {
|
||||
throw new Error(data.message || 'Invalid response from Reddit API')
|
||||
}
|
||||
|
||||
// Process the posts data with proper error handling
|
||||
const posts: RedditPost[] = data.data.children.map((child: any) => {
|
||||
const post = child.data || {}
|
||||
return {
|
||||
id: post.id || '',
|
||||
title: post.title || '',
|
||||
author: post.author || '[deleted]',
|
||||
url: post.url || '',
|
||||
permalink: post.permalink ? `https://www.reddit.com${post.permalink}` : '',
|
||||
created_utc: post.created_utc || 0,
|
||||
score: post.score || 0,
|
||||
num_comments: post.num_comments || 0,
|
||||
selftext: post.selftext || '',
|
||||
thumbnail:
|
||||
post.thumbnail !== 'self' && post.thumbnail !== 'default' ? post.thumbnail : undefined,
|
||||
is_self: !!post.is_self,
|
||||
subreddit: post.subreddit || requestParams?.subreddit || '',
|
||||
subreddit_name_prefixed: post.subreddit_name_prefixed || '',
|
||||
}
|
||||
})
|
||||
|
||||
// Extract the subreddit name from the response data with fallback
|
||||
const subreddit =
|
||||
data.data?.children?.[0]?.data?.subreddit ||
|
||||
(posts.length > 0 ? posts[0].subreddit : requestParams?.subreddit || '')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
subreddit,
|
||||
posts,
|
||||
},
|
||||
}
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || 'Unknown error'
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
subreddit: requestParams?.subreddit || '',
|
||||
posts: [],
|
||||
},
|
||||
error: errorMessage
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'An error occurred while fetching Reddit posts'
|
||||
transformError: (error): string => {
|
||||
// Create detailed error message
|
||||
let errorMessage = error.message || 'Unknown error'
|
||||
|
||||
if (errorMessage.includes('blocked') || errorMessage.includes('rate limited')) {
|
||||
errorMessage = `Reddit access is currently unavailable: ${errorMessage}. Consider reducing request frequency or using the official Reddit API with authentication.`
|
||||
}
|
||||
|
||||
if (errorMessage.includes('not valid JSON')) {
|
||||
errorMessage = 'Unable to process Reddit response: Received non-JSON response, which typically happens when Reddit blocks automated access.'
|
||||
}
|
||||
|
||||
return `Error fetching Reddit posts: ${errorMessage}`
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user