DeepSeek Harness DeepSeek Harness plugin catalog

← Catalog

vision-control

vision-control@0.1.4
loader vision-control

Published Updated

Name, description, and notes are shown in the submitted language and are not translated.

管理 llm-pi-ai 按模型的图片视觉开关;只写自有来源标记的配置,不覆盖用户声明。

For agents: Markdown · JSON · tarball

Install on a machine that already has the plugin market

curl -fsSL https://addon.dshdo.com/install-plugin-market.sh | sh
# then in /plugin-market/ install vision-control and enable it

Open /plugin-market/ → Cloud catalog, install this id, then enable. Install only registers; enable runs it.

Versions

Files

sha256
097cb0b4c5e448440278f0a3147a130f67fdc409b1bdedd3078dab27247cef8a
23861 bytes · package vision-control

README

vision-control

Out-of-tree Cordis plugin that manages the llm-pi-ai image-vision switch per model (no main-program changes, no UI — a pure configuration plane).

Version: 0.1.3

Purpose

Writes to the llm-pi-ai user section through dsh-settings, doing two things:

  • Vision on by default: when a route declares no defaultInput in either

the user section or the composition base layer, write route-level defaultInput: [text, image]. A declared defaultInput (even [text]) is never overwritten.

  • Vision off per model: for models listed in disabled, write `input:

[text] to switch vision off; when a model leaves disabled`, undo only the entry this plugin wrote itself.

Ownership and undo rules (since 0.1.1)

The plugin writes only fields it "owns", and records every write with a deterministic provenance marker:

  • Disabling a model on a hand-declared route (a route whose config carries a

models list) writes input: [text] only when the model entry declares no input, together with the provenance marker _visionControl: { input: true }.

  • Disabling a model on a catalog route (no models list; served from the

installed pi-ai catalog) writes modelOverrides.<id>: { input: [text], _visionControl: { input: true } } only when the authoritative host model catalog does describe that model on that route.

  • Writing route-level defaultInput: [text, image] also records the marker

_visionControl: { defaultInput: true } on the route object.

  • When a disable is lifted or defaultImage is set to false, **only marker

verified writes are removed**. Any unmarked input / defaultInput — including a user-authored input: [text] — is treated as user-owned and is never automatically deleted or rewritten.

  • If the user later edits a value under a marker (an input or a route

defaultInput), the plugin releases ownership of that entry (removes the marker, keeps the user's value) and will not auto-undo it.

  • A route that exists only in the resolved layer (never user-declared) is never

materialized into the user document.

  • Idempotent: repeated loads and repeated reconciles have no side effects;

config validation failures error at load, never silently skipped.

Catalog-route disable verification

Before disabling a model on a catalog route, the plugin verifies membership through the runtime llm service (ctx.get('llm')): the adapter that service materializes for that route is exactly the set of models for which llm-pi-ai would accept a modelOverrides entry. When membership cannot be verified (no llm service, no adapter for the route, or a catalog error), the disable is explicitly refused and logged — never silently treated as applied, which would leave a model looking vision-off while still on. Adapter registration often trails this plugin's mount or a settings edit, so the plugin listens for llm/adapters-updated: a refused catalog disable retries automatically once the adapter is ready instead of staying unapplied.

0.1.3 packaging-only release note

0.1.3 is a packaging-only release: identical plugin code and behavior to 0.1.2. The 0.1.2 archive unintentionally carried an AppleDouble sidecar (._cordis.patch.yml) created by the platform tar tool from a local extended attribute; 0.1.3 is built with the maintained node-tar writer (portable), which never stores macOS filesystem metadata, so the archive contains exactly the intended payload. The 0.1.2 release and its public archive remain immutable history.

0.1.2 fix-release note

0.1.2 fixes a real-framework disposal bug: apply was a constructible function, so Cordis' fiber runner newed it and discarded the async disposer it returns — the "dispose awaits an in-flight settings.replace" guarantee silently never registered when the plugin was unloaded by the actual Loader. apply is now an arrow function (export const apply = …), which Cordis calls directly and whose disposer it collects and awaits. Behavior is otherwise identical to 0.1.1; the 0.1.1 ownership/undo rules and the migration notes below all still apply. The regression is covered by a real-Cordis/Loader fixture test that holds a settings.replace in flight and proves the fiber dispose waits for it, with nothing written after disposal.

0.1.0 → 0.1.1 migration notes

0.1.0's automatic sync deleted user-authored input: [text] / modelOverrides and wrote its values without provenance markers (including route-level defaultInput). After upgrading, which values were originally user-authored cannot be recovered: every unmarked existing value is treated as "user-owned" and is never auto-removed by this plugin (setting defaultImage to false will not undo a route defaultInput that 0.1.0 wrote). If 0.1.0 removed an explicit declaration of yours, restore it by hand (for example, rewrite a model's input as ['text']).

Configuration

In the plugin entry's config (a manual cordis.patch.yml or your config source):

- insert:
    - id: vision-control
      name: vision-control
      config:
        defaultImage: true                      # vision on by default (defaults to true)
        disabled:                               # per-model vision off (optional)
          seawork: [ gpt-5.6-terra ]
          grok: [ grok-imagine ]
  • defaultImage: boolean, defaults to true. When false, route-level

defaults are not written, and undoes route defaultInput values this plugin wrote earlier that still carry the marker (the schema's ['text'] floor resumes); user-declared or 0.1.0-era unmarked values are unaffected.

  • disabled: an array of model ids (applies to every route), or a

provider-keyed map; * matches any route:

  config:
    disabled:
      seawork: [ gpt-5.6-terra ]
      '*': [ shared-model ]
  

Behavior boundaries

  • Writes only the llm-pi-ai namespace's user configuration section; does not

read or write other namespaces and does not touch the main program.

  • Disable writes act only on hand-declared-route model entries or

catalog-route modelOverrides, never writing modelOverrides for a model also listed in a models array (llm-pi-ai rejects that combination).

  • llm-deepseek runs through its own adapter and is outside this plugin's

scope.

  • This plugin is not a vision-content gate; it only keeps llm-pi-ai's model

capability declarations (input / defaultInput) consistent with your configuration intent.