Metadata-Version: 2.5
Name: laidline-vllm
Version: 1.0.0
Summary: vLLM Model Runner V2 logits processor for the text watermark plus an ack-header middleware.
Project-URL: Homepage, https://laidline.com
Project-URL: Documentation, https://laidline.com/docs/quickstart
Project-URL: Changelog, https://laidline.com/docs/changelog
Author: Laidline LLC
License-Expression: LicenseRef-Laidline-Source-Available
License-File: LICENSE
Keywords: ai-act,c2pa,llm,provenance,vllm,watermark
Classifier: Development Status :: 5 - Production/Stable
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.12
Requires-Dist: laidline[text]<2,>=1.0
Description-Content-Type: text/markdown

# laidline-vllm

vLLM Model Runner V2 logits processor for the Laidline text watermark (SynthID or KGW), plus an ack-header middleware. It is the only marking that has to live outside the sidecar.

- Install it into vLLM's environment (it pulls in `laidline[text]`). The entry point `vllm.logits_processors: laidline` loads `LaidlineTextWatermark` with no flag needed; only requests that opt in are marked.
- `LAIDLINE_CONFIG` names the Laidline config. The processor reads `watermark.text` from it. With no config file, or with text watermarking disabled, the processor logs a warning and marks nothing. An invalid config file raises an error.
- It needs a vLLM with the Model Runner V2 logits-processor interface (`vllm.v1.worker.gpu.sample.logits_processor`). No release has it yet (not 0.19.1, not 0.30.0). The build tested on a GPU is nightly `0.30.1rc1.dev86+g5b3f280a6`; export `VLLM_USE_V2_MODEL_RUNNER=1` so vLLM cannot fall back to the V1 runner.
- A request opts in with `vllm_xargs.laidline`, an object with `key_id` and `scheme` (both optional). **Over HTTP, send the object JSON-encoded**, as in `"vllm_xargs": {"laidline": "{\"key_id\": \"k1\", \"scheme\": \"synthid\"}"}`. vLLM's OpenAI server accepts only strings, numbers and lists as `vllm_xargs` values, and answers 400 to a nested object. The Python `LLM` API also takes a plain dict in `SamplingParams.extra_args["laidline"]`. The Laidline proxy sends the JSON form for you.
- SynthID is skipped at temperature 0, so use `scheme: kgw` for greedy traffic. Speculative decoding is not supported: draft rows are left unmarked.
- `--middleware laidline_vllm.middleware.ack_header` adds `x-laidline-watermarked: 1` and `x-laidline-scheme` (the config's scheme, `unknown` without a usable config) to every response. It means "plugin installed", not "this response was marked"; the Laidline proxy treats `unknown` as no ack and checks greedy decoding itself. Use the dotted path: vLLM splits it on the last `.`, in 0.19.1 and in the tested nightly alike. The `module:function` form fails at startup.

Proven live on an RTX 5080 (SynthID and KGW, directly and through the proxy). Full guide: https://laidline.com/docs/integrations/vllm.
