Conversation
1. Redirect console.log to stderr to prevent conflict with MCP StdioServerTransport which hijacks stdout for protocol messages, corrupting both agent output and MCP communication. 2. Wire up the unused lastMentionId field to pass since_id on the mentions API call, avoiding redundant refetches of the same tweets every polling cycle. 3. Add null guard in fetchThread before accessing response.data to prevent null dereference crashes when the API returns unexpected data. 4. Copy the tweets array before sorting in parseThread to avoid mutating the caller's data via Array.sort() in-place side effect. 5. Cap processedMentions Set at 10,000 entries and prune oldest to prevent unbounded memory growth in long-running deployments. https://claude.ai/code/session_015bNhpqRa1sDd4NPLPuZqxV
Summary of ChangesHello @groupthinking, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses several runtime stability and performance issues identified during a debugging pass. The changes focus on robust error handling for API responses, optimizing data fetching to reduce redundant calls, preventing unintended data mutations, and implementing memory management strategies to ensure the application remains stable and efficient over time. These fixes collectively enhance the agent's reliability and resource utilization. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces several important runtime bug fixes that improve the agent's stability, efficiency, and correctness. The changes address potential crashes from null data, prevent a memory leak by capping processed mentions, avoid redundant API calls by using since_id, and prevent data mutation side effects by correctly copying an array before sorting. My review includes a couple of suggestions to further improve code robustness and maintainability.
| const origLog = console.log; | ||
| console.log = (...args: any[]) => console.error(...args); |
There was a problem hiding this comment.
The origLog variable is declared but never used and can be removed.
While redirecting console.log to stderr works, be aware that modifying global objects (monkey-patching) can have unintended side effects in larger applications or when using third-party libraries that might not expect this behavior. It can also complicate debugging. For a more robust solution in the future, consider using a dedicated logging library which allows for flexible stream configuration.
| const origLog = console.log; | |
| console.log = (...args: any[]) => console.error(...args); | |
| console.log = (...args: any[]) => console.error(...args); |
| let mentionsUrl = `https://api.twitter.com/2/users/${userId}/mentions?max_results=10&expansions=author_id&tweet.fields=created_at,conversation_id,in_reply_to_user_id,referenced_tweets`; | ||
| if (this.lastMentionId) { | ||
| mentionsUrl += `&since_id=${this.lastMentionId}`; | ||
| } |
There was a problem hiding this comment.
Building URLs via string concatenation can be fragile and hard to read. Using URLSearchParams provides a more robust and maintainable way to construct URLs with query parameters, as it handles proper encoding and separation of parameters automatically.
const params = new URLSearchParams({
max_results: '10',
expansions: 'author_id',
'tweet.fields': 'created_at,conversation_id,in_reply_to_user_id,referenced_tweets',
});
if (this.lastMentionId) {
params.set('since_id', this.lastMentionId);
}
const mentionsUrl = `https://api.twitter.com/2/users/${userId}/mentions?${params.toString()}`;There was a problem hiding this comment.
Pull request overview
This PR addresses several runtime/operational issues in MyXstack’s polling + MCP runtime by preventing stdout corruption, reducing redundant mention refetching, hardening thread parsing, and bounding in-memory state growth.
Changes:
- Redirects
console.logoutput away from stdout to avoid MCP stdio protocol corruption. - Adds
since_idpagination vialastMentionIdto reduce redundant mention refetches. - Hardens thread parsing (null-guard) and avoids in-place mutation when sorting thread tweets; caps processed mention tracking to prevent unbounded memory growth.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/services/xapi.ts | Adds since_id support, improves thread response guarding, and avoids mutating tweet arrays during sort. |
| src/services/agent.ts | Caps processedMentions to 10,000 entries and prunes oldest IDs. |
| src/index.ts | Redirects console.log to stderr to avoid MCP stdout interference. |
| if (!response || !response.data) { | ||
| console.warn('Invalid response from X API (thread)'); | ||
| return null; | ||
| } | ||
|
|
||
| return this.parseThread(response.data); |
There was a problem hiding this comment.
fetchThread() now only checks response.data for truthiness, but parseThread() expects an array and will still throw if response.data is a non-array object (which can happen with unexpected API shapes). Consider guarding with Array.isArray(response.data) (and returning null otherwise) before calling parseThread().
| // Redirect console.log to stderr so it doesn't conflict with | ||
| // MCP StdioServerTransport which uses stdout for protocol messages | ||
| const origLog = console.log; | ||
| console.log = (...args: any[]) => console.error(...args); | ||
|
|
There was a problem hiding this comment.
origLog is assigned but never used. Either remove it to avoid dead code, or use it to restore console.log during shutdown/after MCP server init (depending on the intended lifecycle).
| const excess = this.processedMentions.size - AutonomousAgent.MAX_PROCESSED_MENTIONS; | ||
| const iter = this.processedMentions.values(); | ||
| for (let i = 0; i < excess; i++) { | ||
| this.processedMentions.delete(iter.next().value as string); |
There was a problem hiding this comment.
The pruning loop deletes iter.next().value as string, which relies on a type assertion and would silently pass undefined if iteration were ever exhausted. Prefer reading { value, done } from iter.next() and breaking if done, which keeps the code type-safe and avoids the assertion.
| this.processedMentions.delete(iter.next().value as string); | |
| const { value, done } = iter.next(); | |
| if (done) { | |
| break; | |
| } | |
| this.processedMentions.delete(value); |
| // Redirect console.log to stderr so it doesn't conflict with | ||
| // MCP StdioServerTransport which uses stdout for protocol messages | ||
| const origLog = console.log; | ||
| console.log = (...args: any[]) => console.error(...args); |
There was a problem hiding this comment.
Unexpected any. Specify a different type.
| console.log = (...args: any[]) => console.error(...args); | |
| console.log = (...args: unknown[]) => console.error(...args); |
| @@ -184,7 +198,7 @@ export class XAPIClient { | |||
| private parseThread(tweets: { created_at: string; [key: string]: any }[]): XThread | null { | |||
There was a problem hiding this comment.
Unexpected any. Specify a different type.
| private parseThread(tweets: { created_at: string; [key: string]: any }[]): XThread | null { | |
| private parseThread(tweets: { created_at: string; [key: string]: unknown }[]): XThread | null { |
Redirect console.log to stderr to prevent conflict with MCP StdioServerTransport which hijacks stdout for protocol messages, corrupting both agent output and MCP communication.
Wire up the unused lastMentionId field to pass since_id on the mentions API call, avoiding redundant refetches of the same tweets every polling cycle.
Add null guard in fetchThread before accessing response.data to prevent null dereference crashes when the API returns unexpected data.
Copy the tweets array before sorting in parseThread to avoid mutating the caller's data via Array.sort() in-place side effect.
Cap processedMentions Set at 10,000 entries and prune oldest to prevent unbounded memory growth in long-running deployments.
https://claude.ai/code/session_015bNhpqRa1sDd4NPLPuZqxV