fix(api): correct plugin dependency id format in snippet DSL extraction#38342
Closed
SquabbyZ wants to merge 2 commits into
Closed
fix(api): correct plugin dependency id format in snippet DSL extraction#38342SquabbyZ wants to merge 2 commits into
SquabbyZ wants to merge 2 commits into
Conversation
Six updated_at Mapped columns in api/models/trigger.py (lines 128, 183, 213, 373, 433, 482) declare: server_default=func.current_timestamp(), server_onupdate=func.current_timestamp(), <-- typo server_onupdate= expects a FetchedValue (DB-side trigger marker), NOT a Python callable. SQLAlchemy silently accepts func.current_timestamp() here, so the column never gets auto-refreshed on ORM UPDATE — updated_at stays frozen at the original row value after every ORM update. The same file already uses the correct onupdate=func.current_timestamp() once on line 534 (WorkflowSchedulePlan.updated_at), proving the typo is inconsistent rather than intentional. All other 70+ models in api/models/ (account, model, tools, provider, dataset, workflow, ...) already use onupdate= uniformly. A seventh column (line 482, AppTrigger.updated_at) used default=naive_utc_now() alongside server_onupdate= — switched to onupdate=naive_utc_now() for symmetry: Python-side default + Python-side onupdate. Impact: the affected models are AppTriggerSubscription, TriggerProviderSubscription, AppTrigger, WorkflowTriggerLog, WorkflowTriggerStatus, AppTrigger (the 6 server_default= sites) and AppTrigger.updated_at. Any ORM-side mutation of these rows in api/services/trigger/* (app_trigger_service.py:39 update(AppTrigger), schedule_service.py, webhook_service.py, etc.) silently leaves updated_at stale. No migration needed — column shape is unchanged, only the auto-refresh behavior on ORM UPDATE is corrected. diff --stat: api/models/trigger.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) Generated via peaks-loop (session 2026-07-02-session-95565c, request 2026-07-02-fix-trigger-models-onupdate-typo). Red-line scope was limited to api/models/trigger.py.
In api/services/snippet_dsl_service.py:577 and :585, the tool and
agent branches of _extract_dependencies_from_workflow_graph() both
build the dependency id with:
dependencies.append(f"{provider_name}/{provider_name}")
That produces ids like 'google/google' (the two halves of the f-string
are the same variable) which never match a real plugin id. The
docstring two lines above explicitly says the expected format is
['langgenius/google'] and the canonical plugin id format is
'{organization}/{plugin_name}', where organization == provider_type
for non-langgenius tools and plugin_name == provider_name.
Introduced during the early Snippet DSL implementation; never fixed
because the buggy ids were silently dropped downstream
(check_dependencies would just report no leaked deps for the typo
output, instead of detecting the actual missing plugin).
This change switches both f-strings to:
f"{provider_type}/{provider_name}"
which matches the docstring and the analyze_tool_dependency() output
in services/plugin/dependencies_analysis.py (which uses
ToolProviderID(tool_id).plugin_id == '{organization}/{plugin_name}').
A regression test is added: a graph with a TOOL node using provider
'google' and an AGENT node using provider 'openai' (both with
provider_type 'langgenius') now extracts ['langgenius/google',
'langgenius/openai']; a TOOL node with only provider_type set (no
provider) is correctly skipped instead of being appended as a
malformed id.
diff --stat:
api/services/snippet_dsl_service.py | 4 ++--
api/tests/unit_tests/services/test_snippet_dsl_service.py | 49 ++++++
2 files changed, 51 insertions(+), 2 deletions(-)
Generated via peaks-loop (session 2026-07-02-session-95565c, request
2026-07-02-fix-snippet-dsl-dependency-id). Red-line scope was limited
to snippet_dsl_service.py and the matching test file.
Member
|
Thanks for the contribution. Before we review this PR, please open an issue first to describe the problem, expected behavior, and proposed approach, then link that issue here. This helps us confirm the scope and align on the fix before moving forward. |
Contributor
Author
|
@crazywoola Thanks for the guidance. Opened issue #38406 describing the malformed plugin id bug ( |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fixes #38406
Summary
In
api/services/snippet_dsl_service.py:577and:585, the tool and agent branches of_extract_dependencies_from_workflow_graph()both build the dependency id with:That produces ids like
google/google(the two halves of the f-string are the same variable) which never match a real plugin id. The docstring two lines above explicitly says the expected format is['langgenius/google']and the canonical plugin id format is{organization}/{plugin_name}, whereorganization == provider_typefor non-langgenius tools andplugin_name == provider_name.Introduced during the early Snippet DSL implementation; never fixed because the buggy ids were silently dropped downstream (check_dependencies would just report no leaked deps for the typo output, instead of detecting the actual missing plugin).
Changes
api/services/snippet_dsl_service.py: switch both f-strings fromf"{provider_name}/{provider_name}"tof"{provider_type}/{provider_name}", which matches the docstring andanalyze_tool_dependency()'s output inservices/plugin/dependencies_analysis.py(which usesToolProviderID(tool_id).plugin_id == '{organization}/{plugin_name}').A regression test is added in
api/tests/unit_tests/services/test_snippet_dsl_service.py:provider='google'and an AGENT node usingprovider='openai'(bothprovider_type='langgenius') now extracts['langgenius/google', 'langgenius/openai'].provider_typeset (noprovider) is correctly skipped instead of being appended as a malformed id.Diff stat
Test plan
pytest api/tests/unit_tests/services/test_snippet_dsl_service.py::test_extract_dependencies_from_workflow_graph_uses_provider_type_and_name -vpasses.test_snippet_dsl_service.pytests continue to pass.langgenius/googleas a dependency.ruff check api/services/snippet_dsl_service.pyclean.Risk / behavior preservation
list[str]and is still called by the same two callers (_extract_dependencies_from_workflowat lines 393 and 534).'google/google') was always a no-op downstream ??it never matched any installed plugin, so the call sites already had no observation of the typo. The corrected output now matches real plugin ids, so any check_dependencies run that was silently passing may now surface legitimate missing-plugin warnings. This is the intended new behavior.Related
peaks-loopsession2026-07-02-session-95565cduring a code-sweep on 2026-07-02.DependenciesAnalysisService.analyze_tool_dependencyinservices/plugin/dependencies_analysis.py??the canonical formatter that this PR brings the snippet path in line with.Automation
Generated via peaks-loop (full-auto mode). Red-line scope was limited to
snippet_dsl_service.pyand the matching test file. Commit message includes the peaks-loop provenance line for traceability.?? Generated with Claude Code via peaks-loop