Skip to content

feat(azure_openai): attach Dify app_id as request metadata (opt-in)#3233

Draft
mas-sakai wants to merge 7 commits into
langgenius:mainfrom
mas-sakai:feat/azure-openai-app-id-metadata
Draft

feat(azure_openai): attach Dify app_id as request metadata (opt-in)#3233
mas-sakai wants to merge 7 commits into
langgenius:mainfrom
mas-sakai:feat/azure-openai-app-id-metadata

Conversation

@mas-sakai

@mas-sakai mas-sakai commented May 31, 2026

Copy link
Copy Markdown

Summary

Adds opt-in support for attaching the Dify app_id as Azure OpenAI request metadata, so per-app usage can be filtered in Stored Completions.

When the new enable_request_metadata credential is set to enabled, the plugin reads app_id from the current Dify session (via get_current_session() from the SDK) and attaches {dify_app_id, dify_source} as the metadata field on both the Chat Completions route (chat.completions.create) and the Responses route (responses.create). The default is disabled, so behavior is unchanged unless the operator opts in.

This is the Azure OpenAI counterpart of the same feature already shipped for Vertex AI (#3168), Bedrock (#3201), and OpenAI (#3203). The responsibility split mirrors those plugins:

Plugin What the plugin attaches What the operator must enable
Vertex AI labels on generateContent BigQuery billing export
Bedrock requestMetadata on Converse CloudWatch invocation logging
OpenAI metadata on Chat / Responses Stored Completions on the OpenAI account — the plugin enables store=true automatically
Azure OpenAI metadata on Chat / Responses Stored Completions on the Azure OpenAI resource — the plugin enables store=true automatically

Design note: store is set to true alongside metadata

E2E verification against a live Azure OpenAI resource showed the API rejects metadata when store is false:

BadRequestError: The 'metadata' parameter is only allowed when 'store' is enabled.

Enabling the metadata feature therefore inherently requires store=true. The plugin makes this explicit: apply_dify_metadata_if_enabled sets store=true alongside the metadata (a non-destructive merge that respects an explicit store value already on the request). This means requests and responses are persisted to Stored Completions on the Azure OpenAI resource when the operator opts in — the same data-storage context as Azure OpenAI's standard logging. Per Microsoft's data privacy documentation, this data stays within the customer's Azure environment: it does not leave Azure and is not used to train foundation models. The credential's help text in provider/azure_openai.yaml documents this storage behavior in both English and Simplified Chinese.

Bedrock (#3201) and Vertex AI (#3168) do not have this constraint, so their plugins remain unchanged.

See:

Related:

Note

Draft / dependency. pyproject.toml temporarily pins dify_plugin to the fork branch ryuta-kobayashi-ug/dify-plugin-sdks@feat/pass-session-to-model-plugins because it carries the get_current_session() API used here (langgenius/dify-plugin-sdks#313). The pin will revert to a versioned dify_plugin spec once that SDK change merges and a release ships.

Change Type

  • Documentation / non-plugin change
  • Non-LLM plugin (tools, extensions, datasource, etc.)
  • LLM plugin

End-to-end verification

Verified end-to-end against a live Azure OpenAI resource ahead of the SDK
dependency (#313). The plugin's metadata-building logic was exercised
directly against chat.completions.create on a deployment with
enable_request_metadata=enabled. Three test requests were persisted to
Stored Completions on the Azure OpenAI resource with the plugin-supplied
metadata intact, retrieved via the GET /openai/v1/chat/completions
listing API (verification UUID 8ec4083b-8e36-4174-a3a2-291e0aba0ec7):

{
  "object": "list",
  "data": [
    {
      "id": "chatcmpl-DoSqrw1FaKzr73LAM3RpfqwBqgkgt",
      "model": "gpt-4o-2024-11-20",
      "metadata": {
        "dify_app_id": "8ec4083b-8e36-4174-a3a2-291e0aba0ec7",
        "dify_source": "dify"
      },
      "choices": [{"index": 0, "message": {"content": "2", "role": "assistant"}, "finish_reason": "stop"}],
      "usage": {"total_tokens": 18, "completion_tokens": 2, "prompt_tokens": 16}
    },
    {
      "id": "chatcmpl-DoSqqQrsQfpfjCT57E0m1Qfhqfs3b",
      "metadata": {
        "dify_app_id": "8ec4083b-8e36-4174-a3a2-291e0aba0ec7",
        "dify_source": "dify"
      },
      "choices": [{"index": 0, "message": {"content": "1", "role": "assistant"}, "finish_reason": "stop"}]
    }
    // and one more, all with the same dify_app_id / dify_source
  ]
}

This also confirms the design note above: the metadata parameter is only
accepted by the Azure OpenAI API when store=true, so the plugin sets both
together. The 400 error reproduced without store=true:

BadRequestError: The 'metadata' parameter is only allowed when 'store' is enabled.

The full Dify-integrated path (where #313 supplies app_id to the plugin
session) will be re-verified once #313 ships, but the plugin's terminal-side
behavior is confirmed working.

LLM Plugin Checklist

Areas affected by this change
  • Message flow (system messages, user ↔ assistant turn-taking)
  • Tool interaction flow (multi-round usage, Agent App and Agent Node)
  • Multimodal input (images, PDFs, audio, video, etc.)
  • Multimodal output (images, audio, video, etc.)
  • Structured output (JSON, XML, etc.)
  • Token consumption metrics
  • Other LLM functionality (reasoning, grounding, prompt caching, etc.) — request metadata for billing/observability
  • New models / model parameter fixes

The change is additive and behind a credential that defaults to disabled. No existing message flow, tool, multimodal, structured-output, or token-accounting code path is altered. Only _chat_generate (Chat Completions route) and _chat_generate_with_responses (Responses route) gain a one-line opt-in hook that mutates the request kwargs immediately before the Azure OpenAI client call. The legacy _generate completions route is intentionally left untouched.

🤖 Generated with Claude Code

mas-sakai and others added 5 commits June 1, 2026 02:59
Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sponses routes

Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mas-sakai mas-sakai temporarily deployed to models/azure_openai May 31, 2026 18:00 — with GitHub Actions Inactive

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for attaching Dify metadata (dify_app_id and dify_source) to Azure OpenAI Chat Completions and Responses API requests. This feature is opt-in and can be enabled via the new enable_request_metadata configuration option. The implementation includes helper functions for metadata normalization and injection, integrated into the LLM generation flows, along with corresponding unit tests and dependency updates. Feedback on the changes suggests avoiding in-place mutation of the existing metadata dictionary to prevent side effects, and adding an explicit check for None in the normalization helper to avoid converting it to the literal string 'None'.

Comment thread models/azure_openai/models/llm/_metadata.py
Comment thread models/azure_openai/models/llm/_metadata.py
…in normalize 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>
@mas-sakai mas-sakai temporarily deployed to models/azure_openai May 31, 2026 18:10 — with GitHub Actions Inactive
mas-sakai added a commit to mas-sakai/dify-official-plugins that referenced this pull request May 31, 2026
…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>
mas-sakai added a commit to mas-sakai/dify-official-plugins that referenced this pull request May 31, 2026
…rmalize 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>
mas-sakai added a commit to mas-sakai/dify-official-plugins that referenced this pull request May 31, 2026
…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>
…behavior

E2E verified that the Azure OpenAI API rejects `metadata` when store is
false (BadRequestError: "The 'metadata' parameter is only allowed when
'store' is enabled."). The metadata feature therefore inherently requires
store=true.

apply_dify_metadata_if_enabled now sets store=true alongside the metadata
(respecting an explicit store value already on the request), and the
credential help text + inline comments document that requests/responses
are persisted to Stored Completions on the Azure OpenAI resource.

Refs: langgenius/dify#35772, langgenius/dify-plugin-sdks#311

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mas-sakai mas-sakai deployed to models/azure_openai June 9, 2026 07:53 — with GitHub Actions Active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant