feat(vertex_ai): support GenerateContentConfig labels for Dify app_id propagation#3168
Draft
mas-sakai wants to merge 13 commits into
Draft
feat(vertex_ai): support GenerateContentConfig labels for Dify app_id propagation#3168mas-sakai wants to merge 13 commits into
mas-sakai wants to merge 13 commits into
Conversation
Add `_labels.py` with `normalize_label_value` and `build_dify_labels` helpers that produce GCP-compliant Vertex AI label dicts. UUID app_ids pass through unchanged; other strings are lowercased, restricted to `[a-z0-9_-]`, and truncated to 63 characters. Unit tests cover passthrough, character replacement, truncation, casing, empty input, and the `None`/ empty short-circuits in `build_dify_labels`. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When `enable_request_metadata` is `enabled` in credentials, attach `dify_app_id` and `dify_source` to `GenerateContentConfig.labels` for the Gemini route only. The `get_current_session` import is local to the call site and wrapped in `try/except ImportError` so the plugin keeps working against older `dify_plugin` releases. With the default `disabled` setting, control flow is identical to the previous version. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add an opt-in `enable_request_metadata` credential (select, defaults to `disabled`) so operators can choose to attach Dify metadata to Vertex AI requests for Cloud Billing breakdown. Existing users who do not touch their credentials are unaffected. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Point `dify_plugin` at the `feat/pass-session-to-model-plugins` branch of `ryuta-kobayashi-ug/dify-plugin-sdks` (PR langgenius#313) so the Gemini route can import `get_current_session()`. Refresh `uv.lock` accordingly. This pin is temporary for the review period; revert to a release-version constraint once langgenius#313 is merged and a new SDK is published. Also add `PR_BODY.md` as a draft of the upstream PR body so it is available alongside the branch. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces the capability to track Cloud Billing costs on a per-application basis by attaching Dify metadata as labels to Vertex AI requests. The implementation includes a utility for normalizing label values according to GCP constraints, logic in the Gemini model to extract session metadata, and a new configuration setting to enable this feature. Feedback suggested optimizing the label normalization helper by truncating long input strings prior to processing to enhance performance and reduce memory usage.
Remove `PR_BODY.md` (and the local `PR_BODY_EN.md` working copy) from the repository. The content lives in the PR description on GitHub; the checked-in copies are working notes that would otherwise land in main with the merge. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The descriptive text for the `enable_request_metadata` credential was placed in `placeholder`, but `type: select` is rendered as a dropdown and does not surface placeholder text. Move the description to `help` so it actually shows in the credentials UI, matching the convention used by the openai provider's select credentials. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Broaden the exception catch around dify_plugin.get_current_session() to `Exception` so that contextvars LookupError, RuntimeError, or any other runtime issue in best-effort telemetry cannot break model generation (previously only ImportError was caught, which left the runtime path unprotected). In normalize_label_value, coerce non-string input via str() before the empty-check so numeric `0` becomes "0" instead of being dropped as falsy. Adds a regression test. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surface zh_Hans copy for the new credential's label, enabled/disabled option labels, and help text. Phrasing follows the Cloud Billing / labels framing of the existing help body, not the Bedrock CloudWatch copy. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
16 tasks
…labels per review - Widen `normalize_label_value` / `build_dify_labels` type hints to `Any` to match the str() coercion the implementations already do. - Reject only `None` and `""` in `build_dify_labels`; other falsy values (e.g. numeric 0) flow through to normalization rather than being silently dropped, matching the design intent for the helper. - Centralize the session lookup + label injection in a new `apply_dify_labels_if_enabled` helper that merges into existing `config_kwargs["labels"]` instead of overwriting it. Aligns with the OpenAI plugin's `apply_dify_metadata_if_enabled` structure. - Add tests covering the merge-with-existing path, the non-dict fallback, the disabled/missing credential no-ops, the session-lookup failure swallowing, and the falsy-but-non-empty input case. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bump vertex_ai manifest from 0.0.54 to 0.0.56 to leapfrog main's 0.0.55 so the marketplace registration does not collide. Adopt upstream's refreshed dependency floors in pyproject.toml while keeping the dify_plugin git+ pin to sdks langgenius#313, then regenerate uv.lock from the merged pyproject. pytest passes (16/16). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses gemini-code-assist suggestion on langgenius#3168: bound the cost of lower() and the regex sub() by slicing the input down to 63 chars first. Keep the trailing truncation because lower() can still expand certain Unicode characters (e.g. German sharp s -> "ss"), so the final cap acts as a defense-in-depth net. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mas-sakai
added a commit
to mas-sakai/dify-official-plugins
that referenced
this pull request
May 27, 2026
Applies the same ordering fix discussed on langgenius#3168 to the Bedrock helper: slice down to 256 chars before the regex sub() so pathological inputs do not incur unbounded regex work. The character set used by sub() replaces 1:1 by length, so the trailing truncation is no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 tasks
…malize per review Per gemini-code-assist on langgenius#3233. Aligns 4 plugins on the same 'no side effects on existing args' principle. Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Note
This is a Draft PR. It depends on
langgenius/dify-plugin-sdks#313
being merged and a new SDK released.
pyproject.toml/uv.lockcurrentlypin
dify_pluginto the #313 branch so the Gemini route can importget_current_session(). The pin will be reverted to a released versionconstraint (
dify_plugin>=0.3.0,<0.6.0) before this PR is marked Readyfor review. The CI "Validate Dependencies" / "Check Plugin Install"
steps may fail until then.
Summary
Enable Cloud Billing visibility per Dify app for the Vertex AI plugin (Gemini
route). When the new
enable_request_metadatacredential is set toenabled,the plugin attaches
dify_app_idanddify_sourcetoGenerateContentConfig.labels, so operators can break Vertex AI cost down bylabels.dify_app_idin GCP Cloud Billing without any ETL.Related issues / PRs:
get_current_session()public API) — this PR depends on itScope (intentionally narrow)
models/llm/llm.py::_generate). The Anthropic-on-Vertexroute (
_generate_anthropic) and other providers are out of scope.dify_app_idanddify_sourceonly.dify_tenant_id/dify_user_idare deferred to a follow-up to keep the surface minimal.enable_request_metadatadefaults todisabled, so existingusers who do not touch their credentials are completely unaffected. With
disabled, the control flow is identical to the previous version.Implementation notes
models/llm/_labels.pywithnormalize_label_valueandbuild_dify_labels. Output conforms to the GCP labels spec (lowercase,[a-z0-9_-]only, 63-char cap). UUID app_ids pass through unchanged.get_current_session()is imported locally inside_generateand wrapped intry/except ImportError, so the plugin keeps working against olderdify_pluginreleases (no hard runtime dependency on fix getnumtoken retrun list[int] #313 once it ships).tests/test_labels.py(passthrough, characterreplacement, truncation, casing, empty input,
None/ empty short-circuitsin
build_dify_labels).Change Type
Screenshots / Videos
🚧 Cloud Billing breakdown screenshots (by
labels.dify_app_id) will beadded once E2E verification completes (currently testing on GCP project
dify-vertex-labels-poc). All 9 unit tests pass (uv run pytest tests/).LLM Plugin Checklist
Areas affected by this change (check all that apply)
Version
versioninmanifest.yaml(not the one undermeta) —0.0.53→0.0.54dify_plugin>=0.3.0,<0.6.0is declared inpyproject.tomland locked inuv.lock(or kept inrequirements.txtfor legacy plugins withoutuv.lock) — SDK docsTesting
dify-vertex-labels-poc)Unit tests:
uv run pytest tests/— 9 passed (label normalization helper).