-
Notifications
You must be signed in to change notification settings - Fork 183
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
Add config classes #591
Add config classes #591
Conversation
@collindutter #635 updated the TextQueryTask to depend on VectorQueryEngine rather than BaseQueryEngine but only added |
6e5639d
to
d2b66fa
Compare
Code changes look great and after playing with the features this is a clear huge step forward. One question @collindutter is that while Tasks look up to Structures to inherit configurations (like Engines), Tools don't do this. Tools also don't have an existing reference to a Structure that they can look to, but is this intentional? It seems like a natural convenience (even if in a later PR) that an Agent, for example, is provided with a configuration and the developer doesn't have to specifically re-wire its Tools. |
Thanks for the feedback and for trying it out! Yes this is something that Tools should also have since they're basically a sibling abstraction to Tasks. I only extended the functionality here because it was already partially implemented in Prompt Task with a look up to Prompt Driver. Agreed that in a future PR we should evaluate how we can better share logic between Tasks and Tools. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Big fan, can't wait to type less.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! Should make it way easier to use and extend the framework!
|
||
@define(kw_only=True) | ||
class AmazonBedrockStructureConfig(BaseStructureConfig): | ||
global_drivers: StructureGlobalDriversConfig = field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename it to global
and StructureGlobalConfig
in case we add more things, other than drivers, to it in the future?
Or should we keep it namespaced to drivers
for clarity and just introduce another config "bundle" in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to keep it namespaced; I could see a singular global
becoming quite unruly.
) | ||
|
||
|
||
@define(kw_only=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we apply this to all new classes in this PR and, in a separate PR, to most (or all?) classes in Griptape?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd actually vote to remove it from this PR, and do it in a single sweep in another.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@define(kw_only=True) | ||
class StructureGlobalDriversConfig(SerializableMixin): | ||
prompt_driver: BasePromptDriver = field( | ||
kw_only=True, default=Factory(lambda: NopPromptDriver()), metadata={"serializable": True} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wanted to make sure this is the best convention...do we like NoOp
, Null
, Dummy
, Stub
, or Empty
better? Or should we stick with Nop
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like Stub
. Nop
and NoOp
feel a bit technical, and Null
feels dangerous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think @andrewfrench?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Traditionally I use Dummy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good with me too. Before I do a big refactor, @vasinov are you also good with Dummy
? DummyPromptDriver
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That works! It's more fun than Stub
and Stub
is too Java-y anyways :)
|
||
|
||
@define(kw_only=True) | ||
class StructureTaskMemoryExtractionEngineConfig(SerializableMixin): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Random thought: will we ever want to use configs as mixins? In other words, will it ever make sense to inherit from two configs at once? If that's the case, should we add the Mixin
suffix to config files and @define(slots=False)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having a difficult time imaging a configuration situation where we'd inherit from multiple. Did you have something specific in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing specific, just wondering. Let's keep it the way it is then :)
class NopImageGenerationDriver(BaseImageGenerationDriver): | ||
model: str = field(init=False) | ||
|
||
def try_text_to_image(self, prompts: list[str], negative_prompts: Optional[list[str]] = None) -> ImageArtifact: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it was established in another PR but why do we prefix those driver methods with try_
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because they have parent methods that wrap them in extra logic. Just following the pattern of other Drivers like try_run
in Prompt Driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it—makes sense!
Literal["256x256"] | Literal["512x512"] | Literal["1024x1024"] | Literal["1024x1792"] | Literal["1792x1024"] | ||
) = field(default="1024x1024", kw_only=True) | ||
response_format: Literal["b64_json"] = field(default="b64_json", kw_only=True) | ||
Union[Literal["256x256"], Literal["512x512"], Literal["1024x1024"], Literal["1024x1792"], Literal["1792x1024"]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we back to Union
over |
everywhere in the framework?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to use Union
for class fields as long as we're supporting python 3.9. We had a slack thread on this somewhere I can try to dig up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes, I remember now.
if self.structure: | ||
self.structure.publish_event(CompletionChunkEvent(token=chunk.value)) | ||
else: | ||
raise ValueError("Streaming requires a structure") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit off: shouldn't prompt drivers still be able to stream regardless of the presence of the structure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, but in the current implementation, publishing events requires a Structure to be set.
I can revert this change since it's kind of out of scope of an already massive PR, but I think we need a separate issue to decouple Prompt Drivers and Structures. Maybe Prompt Drivers take an Event Listener instead.
EDIT: separate issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Let's address it in the separate issue.
def default_config(self) -> BaseStructureConfig: | ||
config = OpenAiStructureConfig() | ||
|
||
if self.prompt_driver is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use a more pythonic @deprecated
decorator for those things:
@property
@deprecated("use `config.global_drivers.prompt_driver` instead.")
def prompt_driver(self) -> Optional[BasePromptDriver]:
return None
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a deprecated
decorator and refactored.
griptape/structures/structure.py
Outdated
if not isinstance(task_memory.query_engine.prompt_driver, NopPromptDriver) | ||
else global_drivers.prompt_driver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we flip it here and below to not use a negative condition, so it's easier to read and reason about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -15,7 +15,9 @@ | |||
class BaseTextInputTask(RuleMixin, BaseTask, ABC): | |||
DEFAULT_INPUT_TEMPLATE = "{{ args[0] }}" | |||
|
|||
_input: str | TextArtifact | Callable[[BaseTask], TextArtifact] = field(default=DEFAULT_INPUT_TEMPLATE) | |||
_input: str | TextArtifact | Callable[[BaseTask], TextArtifact] = field( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Union
here? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of Union
is really only required if the field is marked as serializable. Related to this comment.
6a69dca
to
5c01d68
Compare
Closes #242, #509
This PR introduces the following changes:
Added
OpenAiStructureConfig
for providing Structures with all OpenAi Driver configuration.AmazonBedrockStructureConfig
for providing Structures with all Amazon Bedrock Driver configuration.StructureConfig
for building your own Structure configuration.JsonExtractionTask
for convenience over usingExtractionTask
with aJsonExtractionEngine
.CsvExtractionTask
for convenience over usingExtractionTask
with aCsvExtractionEngine
.Changed
Structure.prompt_driver
in favor ofStructure.global_drivers.prompt_driver
.Structure.embedding_driver
in favor ofStructure.global_drivers.embedding_driver
.Structure.stream
in favor ofStructure.global_drivers.prompt_driver.stream
.TextSummaryTask.summary_engine
now defaults to aPromptSummaryEngine
with a Prompt Driver default ofStructure.global_drivers.prompt_driver
.TextQueryTask.query_engine
now defaults to aVectorQueryEngine
with a Prompt Driver default ofStructure.global_drivers.prompt_driver
and Vector Store Driver default ofStructure.global_drivers.vector_store_driver
.PromptImageGenerationTask.image_generation_engine
now defaults to aPromptImageGenerationEngine
with an Image Generation Driver default ofStructure.global_drivers.image_generation_driver
.VariationImageGenerationTask.image_generation_engine
now defaults to aVariationImageGenerationEngine
with an Image Generation Driver default ofStructure.global_drivers.image_generation_driver
.InpaintingImageGenerationTask.image_generation_engine
now defaults to anInpaintingImageGenerationEngine
with an Image Generation Driver default ofStructure.global_drivers.image_generation_driver
.OutpaintingImageGenerationTask.image_generation_engine
now defaults to anOutpaintingImageGenerationEngine
with an Image Generation Driver default ofStructure.global_drivers.image_generation_driver
.Some usage patterns that come from this:
Configuring a Structure to use Bedrock:
Configuring a Structure to use Anthropic:
Overriding a Structure's Task Memory Query Engine's Embedding Driver:
Modifying an existing config + serializing/deserializing: