Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update IO and improve types, update discord example #64

Merged
merged 4 commits into from
Jan 29, 2025

Conversation

ponderingdemocritus
Copy link
Contributor

@ponderingdemocritus ponderingdemocritus commented Jan 29, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced input/output handler registration with more precise type definitions.
    • Improved streaming support for message handling across different platforms.
  • Improvements

    • Standardized handler naming conventions (renamed handler to execute).
    • Clarified schema definitions by introducing outputSchema.
    • Improved type safety for I/O handlers.
    • Enhanced error handling and logging mechanisms.
  • Changes

    • Updated handler registration interfaces across multiple modules.
    • Refined message processing and validation logic.
  • Refactoring

    • Restructured type definitions for input, output, and action handlers.
    • Simplified subscription management for event-driven handlers.

Copy link

vercel bot commented Jan 29, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
daydreams ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 29, 2025 3:48am

Copy link
Contributor

coderabbitai bot commented Jan 29, 2025

Warning

Rate limit exceeded

@ponderingdemocritus has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab2450 and 2167fa2.

📒 Files selected for processing (1)
  • docs/docs/pages/index.mdx (6 hunks)

Walkthrough

The pull request introduces a comprehensive refactoring of the input/output handler system across multiple files. The primary changes involve renaming handler to execute and schema to outputSchema in handler registrations. This standardizes the naming conventions for input, output, and action handlers across the Daydreams package. The modifications extend to type definitions, orchestrator logic, and example implementations, creating a more consistent and type-safe approach to handling I/O operations.

Changes

File Change Summary
examples/* Renamed handlerexecute and schemaoutputSchema in multiple example files, including example-api.ts, example-basic.ts, example-goal.ts, example-server.ts, example-twitter.ts, and example-discord.ts
packages/core/src/core/types/index.ts Introduced new handler interfaces: InputIOHandler, OutputIOHandler, ActionIOHandler
packages/core/src/core/orchestrator.ts Added unsubscribers map, updated handler execution logic to use execute method
packages/core/src/core/io/discord.ts Enhanced Discord message handling with new streaming methods and updated message schema
packages/core/src/core/processors/* Updated schema processing to use outputSchema in MessageProcessor and ResearchQuantProcessor classes

Sequence Diagram

sequenceDiagram
    participant Client
    participant Orchestrator
    participant IOHandler
    
    Client->>Orchestrator: registerIOHandler
    Orchestrator->>IOHandler: Store handler with execute method
    Client->>Orchestrator: dispatchToInput/Output
    Orchestrator->>IOHandler: Call execute method
    IOHandler-->>Orchestrator: Return processed data
    Orchestrator-->>Client: Provide result
Loading

Possibly related PRs

Poem

🐰 Handlers dance, a new refrain,
Execute and schema, no more pain!
Types align with graceful might,
Daydreams code now shines so bright
A rabbit's code, both clean and light! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (2)
packages/core/src/core/processors/research-processor.ts (1)

Line range hint 205-213: Fix type error in buildHandlerSchemaPart.

The pipeline failure indicates that outputSchema is not defined in the IOHandler type. This needs to be fixed to match the new type system.

Update the IOHandler interface in the types file:

interface IOHandler {
  name: string;
  role: HandlerRole;
+ outputSchema?: z.ZodSchema;
  execute: (data: any) => Promise<any>;
}
🧰 Tools
🪛 GitHub Actions: CI

[error] 205-205: Property 'outputSchema' does not exist on type 'IOHandler'

examples/example-api.ts (1)

Line range hint 96-112: Add error handling for GitHub API requests.

The handler should handle potential API failures, rate limits, and invalid responses.

 execute: async (payload) => {
     const { repo } = payload as { repo: string };
     const response = await fetch(
         `https://api.github.com/repos/${repo}/issues`
     );
+    if (!response.ok) {
+        throw new Error(
+            `GitHub API request failed: ${response.status} ${response.statusText}`
+        );
+    }
     const issues = await response.json();
     return issues;
 },
🧹 Nitpick comments (11)
examples/example-discord.ts (2)

23-23: Consider making the log level configurable.
Currently, LogLevel.DEBUG is hard-coded. For production scenarios, shifting this to an environment variable or config file might be beneficial.

- const loglevel = LogLevel.DEBUG;
+ const loglevel = process.env.LOG_LEVEL 
+     ? LogLevel[process.env.LOG_LEVEL.toUpperCase()] || LogLevel.DEBUG 
+     : LogLevel.DEBUG;

32-33: Caution about purging data.
Purging the vector database on startup is handy for development, but be sure to remove or conditionally execute this in production to avoid unintended data loss.

packages/core/src/core/types/index.ts (3)

536-557: InputIOHandler structure.
Consider adding type parameters to execute and subscribe for stronger typing instead of (data: any) => .... This will help avoid runtime type confusion.

-export interface InputIOHandler extends BaseIOHandler {
+export interface InputIOHandler<T = any> extends BaseIOHandler {
     role: HandlerRole.INPUT;
-    execute?: (data: any) => Promise<unknown>;
+    execute?: (data: T) => Promise<unknown>;
-    subscribe?: (onData: (data: any) => void) => () => void;
+    subscribe?: (onData: (data: T) => void) => () => void;
 }

560-585: OutputIOHandler with enforced output schema.
Terrific for type-safety. Again, consider parameterizing execute to match the schema type.


587-609: ActionIOHandler with optional outputSchema.
If actions require input validation, consider renaming outputSchema to something like actionSchema or paramSchema for clarity. Otherwise, this looks great.

examples/example-basic.ts (2)

89-93: Renaming from “handler” to “execute” alongside “outputSchema.”
The changes are consistent with the new IOHandler architecture. Consider specifying stricter types for data in execute rather than any, ensuring alignment with the Zod schema.


Line range hint 115-128: Renaming to “execute” and “outputSchema” for GraphQL fetch.
Same suggestion: ensure the data in execute matches the shape enforced by outputSchema.

packages/core/src/core/io/discord.ts (1)

125-134: LGTM! Good type safety improvements.

The addition of generic type parameter and proper schema validation enhances type safety.

Consider adding type assertion to ensure T extends MessageData:

-    public createMessageOutput<T>(): IOHandler {
+    public createMessageOutput<T extends MessageData>(): IOHandler {
packages/core/src/core/chain-of-thought.ts (1)

1086-1087: LGTM! Improved type safety and property validation.

The changes correctly implement:

  1. Type casting to OutputIOHandler
  2. Validation of required properties
  3. Standardized naming using outputSchema

However, we could make the error message more descriptive.

Consider improving the error message to be more specific:

-                return `No handler registered for action type "${action.type}" try again`;
+                return `No valid handler registered for action type "${action.type}". Handler must implement 'execute' and 'outputSchema' properties.`;

Also applies to: 1092-1095

examples/example-twitter.ts (2)

Line range hint 138-155: LGTM! Well-structured output handler with proper validation.

The schema correctly validates tweet content for ASCII characters. Consider adding a length validation to ensure tweets don't exceed Twitter's 280-character limit.

 outputSchema: z
     .object({
         content: z
             .string()
+            .max(280, "Tweet content must not exceed 280 characters")
             .regex(
                 /^[\x20-\x7E]*$/,
                 "No emojis or non-ASCII characters allowed"
             ),
     })

Line range hint 167-182: LGTM! Well-structured reply handler with proper validation.

Consider adding the same length validation as suggested for the tweet handler.

 outputSchema: z
     .object({
-        content: z.string(),
+        content: z
+            .string()
+            .max(280, "Tweet content must not exceed 280 characters"),
         inReplyTo: z
             .string()
             .optional()
             .describe("The tweet ID to reply to, if any"),
     })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa77f77 and 418bcec.

📒 Files selected for processing (12)
  • examples/example-api.ts (5 hunks)
  • examples/example-basic.ts (3 hunks)
  • examples/example-discord.ts (3 hunks)
  • examples/example-goal.ts (3 hunks)
  • examples/example-server.ts (1 hunks)
  • examples/example-twitter.ts (4 hunks)
  • packages/core/src/core/chain-of-thought.ts (4 hunks)
  • packages/core/src/core/io/discord.ts (5 hunks)
  • packages/core/src/core/orchestrator.ts (8 hunks)
  • packages/core/src/core/processors/message-processor.ts (4 hunks)
  • packages/core/src/core/processors/research-processor.ts (1 hunks)
  • packages/core/src/core/types/index.ts (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: CI
packages/core/src/core/processors/research-processor.ts

[error] 205-205: Property 'outputSchema' does not exist on type 'IOHandler'

🔇 Additional comments (38)
examples/example-discord.ts (16)

2-4: Documentation looks clear.
No issues found here.


8-8: Import statement confirmed.
No issues found.


20-20: Added Discord.js Message import.
Correct usage, no issues found.


38-38: Sample model usage acknowledged.
No issues found.


42-42: No issues with message processor comment.


49-49: Connecting to MongoDB.
No issues found.


58-58: Clearing tasks.
No concerns.


61-61: Orchestrator creation.
No concerns.


74-74: Discord client initialization.
No concerns.


79-79: Passing loglevel into Discord client.
No concerns.


82-93: Possible mismatch with comment about mentions.
The comment says “On mention, it pipes data,” but the actual logic streams all incoming messages without mention checks. Please verify if this behavior matches your desired design.


98-102: Output handler registration verified.
Looks good. Valid approach to hooking Discord’s message output.


110-113: Console logs for debugging are fine.
No issues found.


115-115: Graceful shutdown comment acknowledged.
No issues found.


119-121: Removing streaming IO handler
This ensures the subscription (and resources) are properly cleaned up. Good approach.


122-122: Verify “discord_reply” handler name.
core.removeIOHandler("discord_reply") assumes the output handler is registered under that name. Confirm that discord.createMessageOutput() uses "discord_reply" internally or rename as needed.

packages/core/src/core/types/index.ts (3)

512-525: Expanded documentation for I/O operations.
No functional issues found; the new doc block clearly explains how to register IO handlers.


528-534: BaseIOHandler introduced.
This is a straightforward interface that standardizes the name property. Looks good.


610-611: Union type for IOHandler.
This unifies all handler types. Good approach.

packages/core/src/core/io/discord.ts (3)

24-32: LGTM! Well-structured schema definition.

The zod schema is clear, well-documented with descriptions, and properly handles optional fields.


100-111: LGTM! Clean implementation of stream cleanup.

The method properly handles the cleanup of message listeners and includes appropriate logging.


136-160: LGTM! Improved error handling and response structure.

The method now provides detailed error information and consistent response structure.

packages/core/src/core/processors/message-processor.ts (4)

3-9: LGTM! Type imports are well-organized.

The addition of ActionIOHandler and OutputIOHandler types improves type safety.


53-54: LGTM! Type definitions are more specific.

Using OutputIOHandler[] and ActionIOHandler[] instead of IOHandler[] provides better type safety.


106-110: LGTM! Clear guidelines for message replies.

The new thinking block provides clear criteria for when to reply to messages:

  1. When mentioned in the message
  2. When able to provide deep help
  3. Never respond to self-messages

66-66: Consider safer type handling instead of non-null assertions.

Using ! assertion operator with outputSchema could lead to runtime errors if the schema is undefined. Consider adding a type guard or providing a default schema.

Also applies to: 72-72

examples/example-goal.ts (1)

107-115: LGTM! Consistent naming conventions.

The renaming of handler to execute and schema to outputSchema improves consistency across the codebase.

Also applies to: 137-150

packages/core/src/core/orchestrator.ts (2)

81-81: LGTM! Improved subscription management.

The addition of the unsubscribers map and proper cleanup in removeIOHandler prevents memory leaks and ensures proper resource management.

Also applies to: 98-111, 124-134


143-143: LGTM! Consistent handler execution checks.

The changes standardize how handler execution is checked and error messages are consistent across different dispatch methods.

Also applies to: 157-162, 182-189, 254-254, 265-265, 537-538, 544-544

packages/core/src/core/chain-of-thought.ts (2)

9-9: LGTM! Type safety improvement.

The addition of OutputIOHandler type import enhances type safety for output handlers.


1150-1160: LGTM! Robust output handling implementation.

The changes effectively:

  1. Implement type-safe output handling
  2. Filter outputs based on schema availability
  3. Generate schema documentation correctly

The implementation is clean and aligns well with the type system.

Also applies to: 1228-1228

examples/example-twitter.ts (2)

Line range hint 95-115: LGTM! Clean implementation of the Twitter mentions input handler.

The handler correctly processes mentions and properly structures the output data.


Line range hint 121-132: LGTM! Clean implementation of the consciousness thoughts input handler.

The handler correctly processes autonomous thoughts and handles empty cases.

examples/example-server.ts (2)

78-85: LGTM! Clean implementation of the user chat input handler.

The schema correctly validates user input and the handler properly passes through the payload.


Line range hint 90-101: LGTM! Clean implementation of the chat reply output handler.

The schema correctly validates the reply structure and the handler properly processes the message.

examples/example-api.ts (3)

Line range hint 117-157: LGTM! Well-implemented universal API call handler.

The handler properly validates input, makes the request, and handles both JSON and text responses with proper error handling.


Line range hint 166-176: LGTM! Clean implementation of the user chat input handler.

The schema correctly validates user input and the handler properly passes through the payload.


Line range hint 181-196: LGTM! Clean implementation of the UI chat reply output handler.

The schema correctly validates the reply structure and the handler properly processes the message.

Comment on lines 85 to 88
if (message.author.displayName == "DeepLoaf") {
console.log("Skipping message from DeepLoaf");
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make the user filter configurable.

The hardcoded check for "DeepLoaf" should be made configurable to improve maintainability and flexibility.

Consider this implementation:

-            if (message.author.displayName == "DeepLoaf") {
-                console.log("Skipping message from DeepLoaf");
-                return;
-            }
+            const ignoredUsers = this.config?.ignoredUsers ?? [];
+            if (ignoredUsers.includes(message.author.displayName)) {
+                this.logger.debug("DiscordClient", `Skipping message from ignored user: ${message.author.displayName}`);
+                return;
+            }

Add the configuration type:

interface DiscordClientConfig {
    ignoredUsers?: string[];
}

Comment on lines +184 to 186
// @ts-ignore - no idea why this is chucking error and i cannot be bothered to fix it
const sentMessage = await channel.send(data.content);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove @ts-ignore by fixing the type assertion.

The @ts-ignore comment should be replaced with proper type handling.

Try this approach:

-            // @ts-ignore - no idea why this is chucking error and i cannot be bothered to fix it
-            const sentMessage = await channel.send(data.content);
+            const sentMessage = await (channel as TextChannel).send(data.content);

Add the import:

import { TextChannel } from "discord.js";

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (9)
examples/example-discord.ts (3)

74-81: Move bot name to environment variables.

The bot name "DeepLoaf" is hardcoded. Consider moving it to environment variables for better configurability.

     const discord = new DiscordClient(
         {
             discord_token: env.DISCORD_TOKEN,
-            discord_bot_name: "DeepLoaf",
+            discord_bot_name: env.DISCORD_BOT_NAME,
         },
         loglevel
     );

83-98: Add type safety to the onData callback.

The onData callback lacks proper typing, which could lead to runtime errors.

     core.registerIOHandler({
         name: "discord_stream",
         role: HandlerRole.INPUT,
-        subscribe: (onData) => {
+        subscribe: (onData: (data: { content: string; channelId: string; sentBy?: string }) => void) => {
             discord.startMessageStream((incomingMessage: Message) => {
                 onData(incomingMessage);
             });
             return () => {
                 discord.stopMessageStream();
             };
         },
     });

Line range hint 116-129: Add error handling to cleanup process.

Consider wrapping the cleanup operations in try-catch blocks to ensure graceful shutdown even if individual cleanup steps fail.

     process.on("SIGINT", async () => {
         console.log(chalk.yellow("\n\nShutting down..."));
 
-        // If we want to stop the streaming IO handler:
-        core.removeIOHandler("discord_stream");
-
-        // Also remove any other handlers or do cleanup
-        core.removeIOHandler("discord_reply");
-        rl.close();
+        try {
+            // If we want to stop the streaming IO handler:
+            await core.removeIOHandler("discord_stream");
+
+            // Also remove any other handlers or do cleanup
+            await core.removeIOHandler("discord_reply");
+            rl.close();
+        } catch (error) {
+            console.error(chalk.red("Error during cleanup:"), error);
+        }
 
         console.log(chalk.green("✅ Shutdown complete"));
         process.exit(0);
     });
packages/core/src/core/io/discord.ts (6)

Line range hint 1-33: Use zod schema to derive MessageData interface.

Consider using zod's type inference to ensure the interface and schema stay in sync.

-export interface MessageData {
-    content: string;
-    channelId: string;
-    conversationId?: string;
-    sendBy?: string;
-}

 export const messageSchema = z.object({
     content: z.string().describe("The content of the message"),
     channelId: z.string().describe("The channel ID where the message is sent"),
     sendBy: z.string().optional().describe("The user ID of the sender"),
     conversationId: z
         .string()
         .optional()
         .describe("The conversation ID (if applicable)"),
 });
+
+export type MessageData = z.infer<typeof messageSchema>;

Line range hint 38-72: Enhance error handling during initialization.

Consider adding retry logic for login and proper cleanup if initialization fails.

     constructor(
         private credentials: DiscordCredentials,
         logLevel: LogLevel = LogLevel.INFO
     ) {
+        if (!credentials.discord_token || !credentials.discord_bot_name) {
+            throw new Error("Missing required credentials");
+        }
+
         this.client = new Client({
             intents: [
                 GatewayIntentBits.Guilds,
                 GatewayIntentBits.GuildMessages,
                 GatewayIntentBits.MessageContent,
                 GatewayIntentBits.GuildMembers,
                 GatewayIntentBits.DirectMessages,
                 GatewayIntentBits.DirectMessageTyping,
                 GatewayIntentBits.DirectMessageReactions,
             ],
             partials: [Partials.Channel],
         });

         this.logger = new Logger({
             level: logLevel,
             enableColors: true,
             enableTimestamp: true,
         });

         this.client.on(Events.ClientReady, () => {
             this.logger.info("DiscordClient", "Initialized successfully");
         });

-        this.client.login(this.credentials.discord_token).catch((error) => {
-            this.logger.error("DiscordClient", "Failed to login", { error });
-            console.error("Login error:", error);
-        });
+        const maxRetries = 3;
+        let retries = 0;
+        
+        const attemptLogin = async () => {
+            try {
+                await this.client.login(this.credentials.discord_token);
+            } catch (error) {
+                this.logger.error("DiscordClient", "Failed to login", { error });
+                if (retries < maxRetries) {
+                    retries++;
+                    this.logger.info("DiscordClient", `Retrying login (${retries}/${maxRetries})...`);
+                    await new Promise(resolve => setTimeout(resolve, 1000 * retries));
+                    return attemptLogin();
+                }
+                throw error;
+            }
+        };
+        
+        attemptLogin().catch((error) => {
+            this.logger.error("DiscordClient", "Failed to initialize after retries", { error });
+            throw error;
+        });
     }

74-116: Improve message stream handling and type safety.

Consider adding more robust message filtering and proper typing for the message stream.

-    public startMessageStream(onData: (data: any) => void) {
+    public startMessageStream(onData: (data: Omit<MessageData, 'conversationId'>) => void) {
         this.logger.info("DiscordClient", "Starting message stream...");
 
         this.messageListener = (message: Message) => {
-            if (
-                message.author.displayName == this.credentials.discord_bot_name
-            ) {
-                console.log(
-                    `Skipping message from ${this.credentials.discord_bot_name}`
-                );
+            if (this.shouldSkipMessage(message)) {
+                this.logger.debug("DiscordClient", "Skipping message", {
+                    author: message.author.displayName,
+                    reason: "bot message"
+                });
                 return;
             }
 
             onData({
                 content: message.content,
                 channelId: message.channelId,
                 sentBy: message.author?.id,
             });
         };
 
         this.client.on(Events.MessageCreate, this.messageListener);
     }
 
+    private shouldSkipMessage(message: Message): boolean {
+        return (
+            message.author.displayName === this.credentials.discord_bot_name ||
+            message.author.bot ||
+            message.content.trim().length === 0
+        );
+    }

121-125: Ensure thorough cleanup in destroy method.

Consider adding checks and proper error handling during cleanup.

     public destroy() {
+        try {
             this.stopMessageStream();
+            this.client.removeAllListeners();
             this.client.destroy();
             this.logger.info("DiscordClient", "Client destroyed");
+        } catch (error) {
+            this.logger.error("DiscordClient", "Error during cleanup", { error });
+            throw error;
+        }
     }

130-139: Improve type safety in createMessageOutput.

Consider constraining the generic type and adding runtime type checking.

-    public createMessageOutput<T>(): IOHandler {
+    public createMessageOutput<T extends MessageData>(): IOHandler {
         return {
             role: HandlerRole.OUTPUT,
             name: "discord_message",
             execute: async (data: T) => {
+                const result = messageSchema.safeParse(data);
+                if (!result.success) {
+                    throw new Error(`Invalid message data: ${result.error}`);
+                }
                 return await this.sendMessage(data as MessageData);
             },
             outputSchema: messageSchema,
         };
     }

Line range hint 141-211: Improve error handling in sendMessage method.

Consider adding more specific error types and better error messages.

+    private class DiscordError extends Error {
+        constructor(message: string, public readonly code?: string) {
+            super(message);
+            this.name = 'DiscordError';
+        }
+    }

     private async sendMessage(data: MessageData): Promise<{
         success: boolean;
         messageId?: string;
         content?: string;
         error?: string;
     }> {
         try {
             this.logger.info("DiscordClient.sendMessage", "Sending message", {
                 data,
             });
 
             if (env.DRY_RUN) {
                 this.logger.info(
                     "DiscordClient.sendMessage",
                     "Dry run enabled",
                     {
                         data,
                     }
                 );
                 return {
                     success: true,
                     messageId: "DRY_RUN",
                     content: "DRY_RUN",
-                    error: "DRY_RUN",
+                    error: undefined,
                 };
             }
 
             if (!data?.channelId || !data?.content) {
-                return {
-                    success: false,
-                    error: "Channel ID and content are required",
-                };
+                throw new DiscordError('Channel ID and content are required', 'MISSING_REQUIRED_FIELDS');
             }
 
             const channel = this.client.channels.cache.get(data?.channelId);
             if (!channel?.isTextBased()) {
-                const error = new Error(
+                throw new DiscordError(
                     `Invalid or unsupported channel: ${data.channelId}`
+                    'INVALID_CHANNEL'
                 );
-                this.logger.error(
-                    "DiscordClient.sendMessage",
-                    "Error sending message",
-                    {
-                        error,
-                    }
-                );
-                throw error;
             }
 
             const sentMessage = await channel.send(data.content);
 
             return {
                 success: true,
                 messageId: sentMessage.id,
                 content: data.content,
                 error: undefined,
             };
         } catch (error) {
             this.logger.error(
                 "DiscordClient.sendMessage",
                 "Error sending message",
                 {
                     error,
                 }
             );
             return {
                 success: false,
-                error: error instanceof Error ? error.message : "Unknown error",
+                error: error instanceof DiscordError
+                    ? `${error.message} (${error.code})`
+                    : error instanceof Error
+                        ? error.message
+                        : "Unknown error",
             };
         }
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 418bcec and 1ab2450.

📒 Files selected for processing (3)
  • examples/example-discord.ts (3 hunks)
  • packages/core/src/core/io/discord.ts (5 hunks)
  • packages/core/src/core/processors/research-processor.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/core/processors/research-processor.ts
🔇 Additional comments (3)
examples/example-discord.ts (2)

1-21: LGTM! Clear documentation and well-organized imports.

The documentation clearly explains the transition to streaming IOHandler, and the imports are appropriately organized.


99-114: LGTM! Clear structure and well-documented setup.

The output handler registration and console setup are well-organized with clear comments explaining each section.

packages/core/src/core/io/discord.ts (1)

189-191: Remove @ts-ignore by fixing the type assertion.

The @ts-ignore comment should be replaced with proper type handling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant