Back to home@MarceloSenai

dsh-plugin-kie-ai

DeepSeek Harness plugin: image and video generation over the KIE AI API

Stars
0
Language
TypeScript
Created
Aug 28, 2026
Updated
Aug 28, 2026

Introduction

dsh-plugin-kie-ai

Image and video generation for a DeepSeek Harness agent, over the KIE AI REST API.

A community plugin, not an official one. It registers three tools on ctx.tools and consumes nothing else — no new capability seam, no change to the agent loop.

ToolWhat it does
kie_generate_imageCreate an image task, poll every 5s until it completes (default 5 min), and return the final image URLs.
kie_generate_videoCreate a video task, poll every 5s until it completes (default 5 min), and return the final video URLs.
kie_task_statusSnapshot one task's status and any asset URLs produced so far — no waiting.

The bearer token is read from the environment per operation (via apiKeyEnv, default KIE_API_KEY). It is never hardcoded, never logged, and never written to a config file.

Install

npm install dsh-plugin-kie-ai

Then add a row to your profile's cordis.patch.yml:

- insert:
    - id: tool-kie-ai
      name: 'dsh-plugin-kie-ai'

Set the key before calling the tools:

export KIE_API_KEY=<your KIE API key>
dsh web

The plugin declares @deepseek-ai/cordis, @deepseek-ai/dsh-tools, and @deepseek-ai/dsh-llm as peers; a harness install already provides them.

Configuration

- id: tool-kie-ai
  config:
    baseUrl: https://api.kie.ai/api/v1
    apiKeyEnv: KIE_API_KEY
    pollIntervalMs: 5000
    pollTimeoutMs: 300000
OptionDefaultMeaning
baseUrlhttps://api.kie.ai/api/v1API base; /jobs/... is appended.
apiKeyEnvKIE_API_KEYEnvironment variable holding the bearer token.
pollIntervalMs5000Delay between status checks.
pollTimeoutMs300000Total polling budget (5 minutes).

How it works

Both generation tools call POST /jobs/createTask and then poll GET /jobs/recordInfo?taskId=... until the task completes, fails, exhausts the budget, or the agent turn is cancelled.

Failures are classified so the model gets something to act on rather than a status code to guess at:

ConditionError kind
HTTP 402/429, or a body mentioning balance or quotainsufficient-balance
A KIE status of failed/error/cancelled/…task-failed
No terminal state within the budgettimeout
The call was aborted by the agentcancelled
A response with no task id, or a success with no URLsprotocol

Responses are parsed defensively: task ids are read from task_id, taskId, id, or those nested in data, and result URLs are discovered by recursing for http(s) strings, bounded to depth 6 and 64 hits.

An unrecognized status is treated as pending, never as failure. The provider adds status strings, and treating an unknown one as terminal would abandon a task that is still running.

What the model reads back

Generated image with nano-banana-pro (task T-9, success):
- https://cdn.example/asset.png
Task T-9: state pending, status rendering

Known limitations

  • A generation holds the turn. Both generation tools poll inside one call, so a five-minute video occupies the tool slot for five minutes. Handing the wait to a background-job seam would fix this and is not what this plugin does.
  • Results are URLs, not attachments. Assets stay at the provider and expire on its schedule. Nothing is admitted to the harness attachment store, so a later turn cannot look at a generated image — only at its link.
  • Model ids pass straight through. An unknown one surfaces as a provider error rather than a refusal at the call.
  • No cost reporting. A generation is billed by the provider and nothing here prices it, so it does not appear in a session's spend report.

Test

npm test

globalThis.fetch is stubbed; nothing reaches the real endpoint. What the tests pin is the reading of the provider format, that the token never appears in what a caller sees, and that the tools register and unregister with the plugin fiber. A live check needs a key and is a manual step.

License

MIT