-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add conversation variable persistence layer #26
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
base: augment_only-issues-20260113-augment-codex-sentry_base_feat_add_conversation_variable_persistence_layer__pr167
Are you sure you want to change the base?
Changes from all commits
335bf83
0fd225a
67007f6
43fefe8
89e644f
3edd525
638b0ef
5ebc87a
89d292e
8505033
36b4a6e
99509eb
2b044dd
2831694
b083fa2
deeebb8
1192648
7c30854
09b7aed
7b19f20
84196e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import logging | ||
|
|
||
| from core.variables import Variable | ||
| from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID | ||
| from core.workflow.conversation_variable_updater import ConversationVariableUpdater | ||
| from core.workflow.enums import NodeType | ||
| from core.workflow.graph_engine.layers.base import GraphEngineLayer | ||
| from core.workflow.graph_events import GraphEngineEvent, NodeRunSucceededEvent | ||
| from core.workflow.nodes.variable_assigner.common import helpers as common_helpers | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class ConversationVariablePersistenceLayer(GraphEngineLayer): | ||
| def __init__(self, conversation_variable_updater: ConversationVariableUpdater) -> None: | ||
| super().__init__() | ||
| self._conversation_variable_updater = conversation_variable_updater | ||
|
|
||
| def on_graph_start(self) -> None: | ||
| pass | ||
|
|
||
| def on_event(self, event: GraphEngineEvent) -> None: | ||
| if not isinstance(event, NodeRunSucceededEvent): | ||
| return | ||
| if event.node_type != NodeType.VARIABLE_ASSIGNER: | ||
| return | ||
| if self.graph_runtime_state is None: | ||
| return | ||
|
|
||
| updated_variables = common_helpers.get_updated_variables(event.node_run_result.process_data) or [] | ||
| if not updated_variables: | ||
| return | ||
|
|
||
| conversation_id = self.graph_runtime_state.system_variable.conversation_id | ||
| if conversation_id is None: | ||
| return | ||
|
|
||
| for item in updated_variables: | ||
| selector = item.selector | ||
| if len(selector) < 2: | ||
| logger.warning("Conversation variable selector invalid. selector=%s", selector) | ||
| continue | ||
| if selector[0] != CONVERSATION_VARIABLE_NODE_ID: | ||
| continue | ||
| variable = self.graph_runtime_state.variable_pool.get(selector) | ||
| if not isinstance(variable, Variable): | ||
| logger.warning( | ||
| "Conversation variable not found in variable pool. selector=%s", | ||
| selector, | ||
| ) | ||
| continue | ||
| self._conversation_variable_updater.update(conversation_id=conversation_id, variable=variable) | ||
| self._conversation_variable_updater.flush() | ||
|
|
||
| def on_graph_end(self, error: Exception | None) -> None: | ||
| pass |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| from sqlalchemy import select | ||
| from sqlalchemy.orm import Session | ||
|
|
||
| from core.variables.variables import Variable | ||
| from extensions.ext_database import db | ||
| from models import ConversationVariable | ||
|
|
||
|
|
||
| class ConversationVariableNotFoundError(Exception): | ||
| pass | ||
|
|
||
|
|
||
| class ConversationVariableUpdaterImpl: | ||
| def __init__(self) -> None: | ||
| self._pending_updates: list[tuple[str, Variable]] = [] | ||
|
|
||
| def update(self, conversation_id: str, variable: Variable) -> None: | ||
| self._pending_updates.append((conversation_id, variable)) | ||
|
|
||
| def flush(self) -> None: | ||
| for conversation_id, variable in self._pending_updates: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🤖 Was this useful? React with 👍 or 👎 |
||
| stmt = select(ConversationVariable).where( | ||
| ConversationVariable.id == variable.id, ConversationVariable.conversation_id == conversation_id | ||
| ) | ||
| with Session(db.engine) as session: | ||
| row = session.scalar(stmt) | ||
| if not row: | ||
| raise ConversationVariableNotFoundError("conversation variable not found in the database") | ||
| row.data = variable.model_dump_json() | ||
| session.commit() | ||
|
|
||
|
|
||
| def conversation_variable_updater_factory() -> ConversationVariableUpdaterImpl: | ||
| return ConversationVariableUpdaterImpl() | ||
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.
updated_variablesis built fromoriginal_variable, soUpdatedVariable.new_valuewill reflect the pre-update value rather than what was written to the pool (updated_variable). This can break downstream consumers that rely onprocess_datato represent the post-write state.🤖 Was this useful? React with 👍 or 👎