Skip to content

feat(dify): identify plugin requests with X-TF-Client-Name/Version - #36

Open
londondavila wants to merge 4 commits into
mainfrom
london/dify-client-headers
Open

feat(dify): identify plugin requests with X-TF-Client-Name/Version#36
londondavila wants to merge 4 commits into
mainfrom
london/dify-client-headers

Conversation

@londondavila

@londondavila londondavila commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Search and Fetch calls from the Dify plugin arrive with client_name null, so in telemetry they sit inside the untagged request_origin=api bucket indistinguishable from a hand-written script. Runs were already attributed through the api_integration payload field, but search/fetch and the GET tools have no body to carry it. The server reads X-TF-Client-Name / X-TF-Client-Version on every route (request-source.ts:160), and this plugin hits agent.tinyfish.ai directly.

  • _api_headers adds X-TF-Client-Name: dify (bare token, same as the existing api_integration) and X-TF-Client-Version from manifest.yaml; both call sites (_tf_request, run_sse stream) already use it
  • PLUGIN_VERSION = yaml.safe_load(manifest)["version"] — pyyaml is the loader the Dify daemon uses on this file and was already a hard transitive dep; now explicit in requirements.txt. Path resolution verified against the daemon's packager/loader: manifest.yaml at the .difypkg root, tools/ one level below, in every runtime mode
  • bump 0.0.4 → 0.0.5 in both manifest version fields, matching prior bumps
  • .difyignore: tests/, so the new tests don't ship in the marketplace artifact
  • tests/test_headers.py: header contract; PLUGIN_VERSION is a real semver present at column 0 of the manifest
  • X-TF-Request-Origin deliberately unset — api stays the transport

Prerequisites / footguns

  • Attributes new traffic only; existing installs stay unattributed until users update.
  • The Dify publish workflow never runs. It lives at dify/.github/workflows/plugin-publish.yml, not the repo root, so GitHub ignores it; marketplace republish is a manual step. Pre-existing, out of scope here, worth its own fix.
  • The tests run nowhere automatically: no Dify test workflow, and httpx is only transitive. uv run --with pytest --with httpx --with pyyaml pytest dify/tests.
  • client_name is self-reported. Analytics only, never auth or billing.
  • ruff findings in tools/run_*.py / get_run.py / list_runs.py are pre-existing and untouched.

Testing: pytest 2 passed, from dify/ and from the repo root.

🤖 Generated with Claude Code

https://claude.ai/code/session_0138Vn8E8TfZkUWd3StqDgjp

londondavila and others added 4 commits September 1, 2026 11:39
Search and Fetch calls from this plugin land in TinyFish telemetry as
untagged request_origin=api. Runs were already tagged via the
api_integration payload field, but search/fetch have no payload to carry
it. The server reads X-TF-Client-Name / X-TF-Client-Version on every route.

- _api_headers adds X-TF-Client-Name: tinyfish-dify and
  X-TF-Client-Version read from manifest.yaml; both call sites
  (_tf_request and run_sse's stream) already use it
- tools/constants.PLUGIN_VERSION parsed from the manifest so the header
  cannot drift from the published version
- bump 0.0.4 → 0.0.5 (both manifest version fields, matching prior bumps)
- tests/test_headers.py: header contract and version/manifest agreement

X-TF-Request-Origin deliberately unset: `api` stays the transport.
Attributes new traffic only; needs a marketplace republish.

Testing: pytest 2 passed. Repo has no dify lint/test CI; ruff findings in
untouched tool files are pre-existing.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138Vn8E8TfZkUWd3StqDgjp
Review fixes. The packager honors .difyignore only, so tests/ was shipping in
the marketplace artifact. The manifest test re-parsed the file the same way
the constant does and opened it relative to cwd, so it could only fail by
being run from the wrong directory.

- .difyignore: tests/
- test asserts a real semver and that the manifest carries it, path resolved
  from __file__
- comment: request_origin stays `api`; what changes is client_name

Testing: pytest 2 passed from dify/ and from the repo root.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138Vn8E8TfZkUWd3StqDgjp
The substring check also matched the indented meta.version line.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138Vn8E8TfZkUWd3StqDgjp
Aligns X-TF-Client-Name with the repo contract (bare token, same as
api_integration) and replaces the hand-rolled version scanner with
yaml.safe_load — pyyaml is already a hard dependency of dify_plugin and is
the loader the Dify daemon uses on the same file.

- X-TF-Client-Name: dify
- constants: yaml.safe_load(manifest)["version"], 0+unknown on any failure
- requirements: pyyaml explicit instead of transitive
- test: column-0 anchor on the manifest check

Testing: pytest 2 passed (uv run --with pytest --with httpx --with pyyaml).

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138Vn8E8TfZkUWd3StqDgjp
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 51 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 52 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Essentials

Run ID: 43517c01-97f5-441e-9b2f-cc5c5cffdb4c

📥 Commits

Reviewing files that changed from the base of the PR and between 496cd63 and b7947fd.

📒 Files selected for processing (7)
  • dify/.difyignore
  • dify/manifest.yaml
  • dify/requirements.txt
  • dify/tests/__init__.py
  • dify/tests/test_headers.py
  • dify/tools/base.py
  • dify/tools/constants.py

Comment @coderabbitai help to get the list of available commands.

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