feat: introduce Dependency Injection to enhance developer experience
Relates to
No issue
Risks
Low.
This is a brand new feature.
It is only effective when using dependency injection to load a Class rather than an Object within the plugin.
Background
What does this PR do?
It provides dependency injection-driven object management functions for Eliza's plugin system, enabling Providers, Actions, and Evaluators in the plugin to be initialized in a dynamic way.
It also enables these objects to support multiple existence modes such as Singleton and onRequest, making instance management more flexible.
An abstract class of BaseInjectableAction is created at the same time. Through the @property decorator, the generation of ContentClass and its Template becomes more automated without the need for additional manual creation.
If you want to use this di plugin, your plugin exports will look like:
import { CreateResourceAction } from "./sampleAction";
import { SampleProvider } from "./sampleProvider";
import { SampleEvaluator } from "./sampleEvalutor";
import { PluginOptions } from "../types";
export const samplePlugin: PluginOptions = {
name: "sample",
description: "Enables creation and management of generic resources",
actions: [CreateResourceAction],
providers: [SampleProvider],
evaluators: [SampleEvaluator],
// separate examples will be added for services and clients
services: [],
clients: [],
};
export default samplePlugin;
All the actions, providers, evaluators are Class instead of Object.
So the normalization process is added to agent/src/index.ts's startAgents method:
import { normalizeCharacter } from "@elizaos/plugin-di";
const startAgents = async () => {
// ...
if (charactersArg) {
characters = await loadCharacters(charactersArg);
}
// Normalize characters for injectable plugins
characters = await Promise.all(characters.map(normalizeCharacter));
// ....
}
This normalizeCharacter method will normalize the plugin with dependency injection Class to the normal plugin.
What kind of change is this?
Features (non-breaking change which adds functionality)
Why are we doing this? Any context or related work?
- The
ActionandProviderin some plugins hope to be initialized in a dynamic way rather than directly exporting an object. - Some
Providers may be shared among multiplePlugins. They need to exist in aSingletoninstance rather than creating an instance for each plugin. - There are many elements in
Actionthat can be automated through decorator definitions, and this plugin provides a convenient abstract class.
Documentation changes needed?
My changes require a change to the project documentation.
Testing
Where should a reviewer start?
pnpm test --filter=@elizaos/plugin-di
Detailed testing steps
run test cases
Discord username
bt.wood
@coderabbitai review
@coderabbitai review
๐ Walkthrough
Walkthrough
The pull request introduces a new Dependency Injection (DI) plugin for the Eliza framework, adding comprehensive infrastructure for creating modular and injectable plugins. The changes span multiple files across the packages/plugin-di directory, establishing a robust system for managing actions, evaluators, providers, and plugin creation using Inversify and TypeScript decorators. Additionally, updates include new configuration files, example implementations, and tests to enhance usability and validation.
Changes
| File | Change Summary |
|---|---|
agent/package.json |
Added @elizaos/plugin-di workspace dependency. |
agent/src/index.ts |
Integrated normalizeCharacter function for plugin normalization. |
packages/plugin-di/* |
Comprehensive new package with DI plugin implementation, including decorators, factories, types, and example implementations. |
packages/_examples/plugin/src/plugins/samplePlugin.ts |
Fixed import statement for sample evaluator. |
๐ Recent review details
Configuration used: CodeRabbit UI Review profile: CHILL Plan: Pro
๐ฅ Commits
Reviewing files that changed from the base of the PR and between c22aa1ef26af1a68d2fc8422b14150f19c2f6733 and 20578fb46a5287424f4941ec5038c2b8fb68d83f.
โ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
๐ Files selected for processing (2)
agent/package.json(1 hunks)agent/src/index.ts(2 hunks)
๐ง Files skipped from review as they are similar to previous changes (2)
- agent/src/index.ts
- agent/package.json
๐ชง Tips
Chat
There are 3 ways to chat with CodeRabbit:
โผ๏ธ IMPORTANT Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin 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
@coderabbitaiin 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 pauseto pause the reviews on a PR.@coderabbitai resumeto resume the paused reviews.@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository.@coderabbitai full reviewto do a full review from scratch and review all the files again.@coderabbitai summaryto regenerate the summary of the PR.@coderabbitai generate docstringsto generate docstrings for this PR. (Beta)@coderabbitai resolveresolve all the CodeRabbit review comments.@coderabbitai configurationto show the current CodeRabbit configuration for the repository.@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile 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.
Resolved reviews from @coderabbitai
@btspoony thanks for resolving the reviews! i'll take another look at the changes.
:white_check_mark: Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Resolved reviews from @coderabbitai
@btspoony thanks for resolving the reviews! i'll review the changes again.
:white_check_mark: Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Resolved reviews @coderabbitai
@btspoony thanks for resolving the reviews! i'll take another look at the changes.
/) /) ( . . ) ( >โก ) u u
:white_check_mark: Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Resolved reviews @coderabbitai cc @wtfsayo
@btspoony thanks for resolving the reviews! i'll take another look at the changes.
๐ฐ (๏ฝกโโฟโ๏ฝก) โก
:white_check_mark: Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
I'm going to look into this.
I will keep this branch updated daily. If there is anything else I need to do to get this merged, please let me know. @shakkernerd
@coderabbitai security and second order effect analysis please
[!TIP] For best results, initiate chat on the files or code changes.
@wtfsayo Here's the security and second-order effect analysis of the dependency injection implementation:
Security Analysis:
-
โ Container Security
- Proper scope isolation between singleton and request-scoped instances
- No container leaks detected
- No unsafe code execution patterns (eval, Function constructor)
-
โ ๏ธ Type Safety Concerns
- Multiple
as anytype assertions found throughout the codebase - Plugin normalization accepts
anytype input - Recommend adding runtime type validation using Zod schemas
- Multiple
-
โ Dependency Security
- All dependencies are on stable versions
- Core dependencies (inversify, zod) are well-maintained
- No known vulnerabilities in pinned versions
Second-Order Effects:
-
๐ Runtime Behavior
- All characters now undergo normalization process
- Plugins are instantiated per request (isolated state)
- Potential performance impact from additional normalization step
-
๐ง Memory Management
- Request-scoped instances prevent state leakage
- Singleton scope used appropriately for shared resources
- No detected memory leak patterns
Recommendations:
- Enhance type safety:
- Reduce
as anyusage - Add Zod schemas for plugin validation
- Reduce
- Add monitoring for:
- Plugin normalization performance
- Memory usage patterns in singleton instances
- Consider adding a plugin validation phase before normalization
Would you like me to open a GitHub issue for tracking these recommendations?
๐ Analysis chain
๐ Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for potential security issues in dependency injection
echo "Checking for eval usage..."
rg "eval\(" --type ts
echo -e "\nChecking for Function constructor usage..."
rg "new Function" --type ts
echo -e "\nChecking for dynamic imports..."
rg "import\(.*\)" --type ts
echo -e "\nChecking for prototype pollution vectors..."
rg "Object\.prototype" --type ts
rg "Object\.assign" --type ts
echo -e "\nChecking package.json for dependency versions..."
cat packages/plugin-di/package.json | jq '.dependencies, .devDependencies'
echo -e "\nChecking for potential memory leaks in singleton patterns..."
ast-grep --pattern 'class $_ {
$$$
private static $_: any;
$$$
}'
echo -e "\nChecking for unsafe type assertions..."
rg "as any" --type ts
Length of output: 15461
Script:
#!/bin/bash
# Check plugin normalization and DI container setup
echo "Analyzing plugin normalization..."
ast-grep --pattern 'async function normalizePlugin($_, $_) {
$$$
}'
echo -e "\nAnalyzing DI container configuration..."
ast-grep --pattern 'container.bind($_).to($_)'
echo -e "\nChecking for container scope definitions..."
rg "inSingletonScope|inRequestScope|inTransientScope" --type ts
echo -e "\nChecking for potential container leaks..."
rg "container\.get|container\.resolve" --type ts
Length of output: 1062
Script:
#!/bin/bash
# Check plugin normalization implementation
echo "Analyzing plugin normalization implementation..."
rg -A 10 "async function normalizePlugin" --type ts
echo -e "\nChecking for plugin validation..."
rg -A 5 "function isValidPlugin" --type ts
echo -e "\nAnalyzing character normalization..."
rg -A 10 "async function normalizeCharacter" --type ts
Length of output: 1340