-
Notifications
You must be signed in to change notification settings - Fork 51
feat: 🔌 Initial plugin system implementation #23
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
Merged
johnnygreco
merged 27 commits into
main
from
johnny/feat/14-initial-plugin-system-implementation
Nov 11, 2025
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
8d99604
separate column configs and types
johnnygreco 8604dc1
create plugin object
johnnygreco 3223d12
create plugin manager
johnnygreco ef5ece6
fix config integration
johnnygreco e648aa9
make base task registry raise on collision false by default
johnnygreco 15ed0f8
update registry test after raise on collision default update
johnnygreco feb9817
make analysis work using general stats calculation
johnnygreco a00e858
default -> builtin
johnnygreco 74d3308
use entry point approach instead
johnnygreco 1ec27fd
rewire using plugin helpers
johnnygreco e648b0f
add env var to disable plugins
johnnygreco f7e708a
fix tests
johnnygreco f3e392e
update plugin manager tests
johnnygreco 6a9b011
add tests for plugin helpers
johnnygreco be273b0
update license headers
johnnygreco 808fd0c
add emoji
johnnygreco c987509
not using the pm in the builder code
johnnygreco dcc6ee8
Update src/data_designer/plugins/manager.py
johnnygreco 43c8f5d
Update src/data_designer/plugins/manager.py
johnnygreco 34084ad
Update src/data_designer/plugins/manager.py
johnnygreco ba06651
merge plugin registry into the manager
johnnygreco 31a1d9b
small pr feedback
johnnygreco cd4183b
client side plugin manager
johnnygreco 4bccea7
builtin -> default; move adding plugins to registry
johnnygreco c752bd4
update method names to better match what they do
johnnygreco cea9209
use register verb for consistency with other registries
johnnygreco 2b44686
thread safety updates; make discover private
johnnygreco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| from abc import ABC | ||
| from typing import Literal, Optional, Type, Union | ||
|
|
||
| from pydantic import BaseModel, Field, model_validator | ||
| from typing_extensions import Self | ||
|
|
||
| from .base import ConfigBase | ||
| from .errors import InvalidConfigError | ||
| from .models import ImageContext | ||
| from .sampler_params import SamplerParamsT, SamplerType | ||
| from .utils.code_lang import CodeLang | ||
| from .utils.constants import REASONING_TRACE_COLUMN_POSTFIX | ||
| from .utils.misc import assert_valid_jinja2_template, get_prompt_template_keywords | ||
| from .validator_params import ValidatorParamsT, ValidatorType | ||
|
|
||
|
|
||
| class SingleColumnConfig(ConfigBase, ABC): | ||
| name: str | ||
| drop: bool = False | ||
| column_type: str | ||
|
|
||
| @property | ||
| def required_columns(self) -> list[str]: | ||
| return [] | ||
|
|
||
| @property | ||
| def side_effect_columns(self) -> list[str]: | ||
| return [] | ||
|
|
||
|
|
||
| class SamplerColumnConfig(SingleColumnConfig): | ||
| sampler_type: SamplerType | ||
| params: SamplerParamsT | ||
| conditional_params: dict[str, SamplerParamsT] = {} | ||
| convert_to: Optional[str] = None | ||
| column_type: Literal["sampler"] = "sampler" | ||
|
|
||
|
|
||
| class LLMTextColumnConfig(SingleColumnConfig): | ||
| prompt: str | ||
| model_alias: str | ||
| system_prompt: Optional[str] = None | ||
| multi_modal_context: Optional[list[ImageContext]] = None | ||
| column_type: Literal["llm-text"] = "llm-text" | ||
|
|
||
| @property | ||
| def required_columns(self) -> list[str]: | ||
| required_cols = list(get_prompt_template_keywords(self.prompt)) | ||
| if self.system_prompt: | ||
| required_cols.extend(list(get_prompt_template_keywords(self.system_prompt))) | ||
| return list(set(required_cols)) | ||
|
|
||
| @property | ||
| def side_effect_columns(self) -> list[str]: | ||
| return [f"{self.name}{REASONING_TRACE_COLUMN_POSTFIX}"] | ||
|
|
||
| @model_validator(mode="after") | ||
| def assert_prompt_valid_jinja(self) -> Self: | ||
| assert_valid_jinja2_template(self.prompt) | ||
| if self.system_prompt: | ||
| assert_valid_jinja2_template(self.system_prompt) | ||
| return self | ||
|
|
||
|
|
||
| class LLMCodeColumnConfig(LLMTextColumnConfig): | ||
| code_lang: CodeLang | ||
| column_type: Literal["llm-code"] = "llm-code" | ||
|
|
||
|
|
||
| class LLMStructuredColumnConfig(LLMTextColumnConfig): | ||
| output_format: Union[dict, Type[BaseModel]] | ||
| column_type: Literal["llm-structured"] = "llm-structured" | ||
|
|
||
| @model_validator(mode="after") | ||
| def validate_output_format(self) -> Self: | ||
| if not isinstance(self.output_format, dict) and issubclass(self.output_format, BaseModel): | ||
| self.output_format = self.output_format.model_json_schema() | ||
| return self | ||
|
|
||
|
|
||
| class Score(ConfigBase): | ||
| name: str = Field(..., description="A clear name for this score.") | ||
| description: str = Field(..., description="An informative and detailed assessment guide for using this score.") | ||
| options: dict[Union[int, str], str] = Field(..., description="Score options in the format of {score: description}.") | ||
|
|
||
|
|
||
| class LLMJudgeColumnConfig(LLMTextColumnConfig): | ||
| scores: list[Score] = Field(..., min_length=1) | ||
| column_type: Literal["llm-judge"] = "llm-judge" | ||
|
|
||
|
|
||
| class ExpressionColumnConfig(SingleColumnConfig): | ||
| name: str | ||
| expr: str | ||
| dtype: Literal["int", "float", "str", "bool"] = "str" | ||
| column_type: Literal["expression"] = "expression" | ||
|
|
||
| @property | ||
| def required_columns(self) -> list[str]: | ||
| return list(get_prompt_template_keywords(self.expr)) | ||
|
|
||
| @model_validator(mode="after") | ||
| def assert_expression_valid_jinja(self) -> Self: | ||
| if not self.expr.strip(): | ||
| raise InvalidConfigError( | ||
| f"🛑 Expression column '{self.name}' has an empty or whitespace-only expression. " | ||
| f"Please provide a valid Jinja2 expression (e.g., '{{ column_name }}' or '{{ col1 }} + {{ col2 }}') " | ||
| "or remove this column if not needed." | ||
| ) | ||
| assert_valid_jinja2_template(self.expr) | ||
| return self | ||
|
|
||
|
|
||
| class ValidationColumnConfig(SingleColumnConfig): | ||
| target_columns: list[str] | ||
| validator_type: ValidatorType | ||
| validator_params: ValidatorParamsT | ||
| batch_size: int = Field(default=10, ge=1, description="Number of records to process in each batch") | ||
| column_type: Literal["validation"] = "validation" | ||
|
|
||
| @property | ||
| def required_columns(self) -> list[str]: | ||
| return self.target_columns | ||
|
|
||
|
|
||
| class SeedDatasetColumnConfig(SingleColumnConfig): | ||
| column_type: Literal["seed-dataset"] = "seed-dataset" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.