TGYD-helige/dsh-plugins

dsh-plugins

Generic DeepSeek Harness (dsh) plugins: A2A protocol server, session storage mirror, and Langfuse observability.

待分类agent2agentai-agentscordis

dsh-plugins

Composable, config-driven plugins for DeepSeek Harness (dsh). Each package is a publishable dsh bundle: install only what an agent needs, configure it through Cordis, and keep dsh itself unpatched.

Packages

Package · What it does · Primary seams @amaster.ai/dsh-a2a · Serves dsh agents over the A2A protocol 1.0 (JSON-RPC + SSE, with a v0.3 compatibility layer): streaming turns, task cancel, task list, tool approvals, agent card, opt-in native inbox execution; pluggable task-state stores (memory/filesystem/Redis/GCS + workspace archive) · ctx.agents, session/event, approval/request, own HTTP server @amaster.ai/dsh-storage · Mirrors the session event stream into MySQL/PostgreSQL/SQLite/SQL Server (ai_messages / ai_chat_histories) · session/event tap (local persistence stays authoritative) @amaster.ai/dsh-langfuse · Langfuse observability: one generation per LLM call (plus a nested llm-request span with the verbatim loop-built request), one span per tool call or hook run, one trace per turn; subagent child sessions nested under the parent's tree · llm/stream, tools/pre-execute → tools/result, session/event (including hook/*), session/created + subagent/start/subagent/end @amaster.ai/dsh-policy · Declarative tool-call policy: config-driven allow/deny/ask rules (tool name, args pattern, per-segment shell command prefix/regex, priority) — Gemini CLI-style policy files as plain plugin config · tools/pre-execute waterfall (ask rides dsh's approval seam) @amaster.ai/dsh-subagent-filesystem · Discovers Markdown specialist roles through the caller's filesystem and delegates through native in-process subagents · ctx.fs, scoped ctx.tools / ctx.systemPrompt, agent/created, ctx.subagents

Plugin previews

dsh-a2a dsh-storage dsh-langfuse dsh-policy dsh-subagent-filesystem

Status

This is an early dsh-preview ecosystem. The plugin shapes, config schemas, and seam choices are in place; event-payload field names are marked TODO(verify) where dsh pre-release APIs may shift. Pin your dsh version and check those markers before production use.

Compatibility

@amaster.ai/dsh-* · dsh · cordis · @a2a-js/sdk (dsh-a2a) 0.1.x · >=0.1.5-rc.1 · >=0.1.6-alpha.1 · >=0.1.7-alpha.1 · >=0.2.0-rc.1 · >=0.2.1-rc.1 (peer floor) / 0.2.1-rc.3 (tested) · ^4.0.1 (tested 4.0.5) · ^1.1.0 (A2A 1.0 + v0.3 compat)

dsh is in developer preview and will break compatibility between releases. Plugins declare the oldest compatible dsh version as a fixed peer floor and every release records the tested dsh version in this matrix; the floor moves only when a plugin starts requiring a newer dsh API. Installs ride dsh plugin add, which is pnpm-only — pnpm's peer matching has no prerelease gate, so any newer dsh (alpha or stable) satisfies the floor without warnings. npm consumers are gated differently: npm never lets a prerelease satisfy a range unless the range names that release tuple with a prerelease comparator, so the peer ranges also name the 0.1.6, 0.1.7, 0.2.0, and 0.2.1 prerelease tuples. Drop each union member once that line ships a final release.

dsh-a2a inbox execution additionally tests the unmodified official DSH 0.2.1-rc.3 npm runtime. Its agent peer floor is >=0.2.0-rc.2 || >=0.2.1-alpha.1, for the public send/claim/pre-step interfaces. Queueing uses Agent.send; no core patch is required.

dsh-a2a's optional Goal integration consumes @deepseek-ai/dsh-goal >=0.2.0-rc.2 || >=0.2.1-alpha.1 and preserves official Goal round validation (tested with the Goal service and round driver at 0.2.1-rc.3).

dsh-a2a's approval bridge has an optional @deepseek-ai/dsh-user-approval peer floor of >=0.1.6-alpha.2 || >=0.1.7-alpha.1 || >=0.2.0-rc.1 || >=0.2.1-rc.1 (tested at 0.2.1-rc.3).

dsh-a2a requires @deepseek-ai/dsh-session >=0.2.0-rc.1: optional subagent tool streaming uses the session lifecycle offset to distinguish newly created children from restored sessions, preventing false delegation attribution. Other dsh peer floors remain unchanged apart from the agent floor above.

dsh-langfuse's optional image display uses @deepseek-ai/dsh-attachment >=0.2.0-rc.1 (tested at 0.2.1-rc.3); metadata-only tracing does not require an attachment backend.

dsh-subagent-filesystem requires @deepseek-ai/dsh-subagent >=0.2.1-rc.2 (tested at 0.2.1-rc.3) and the native in-process spawn provider. It supports foreground reports and continuable background children; Markdown definitions cannot override models, tools, or permissions.

Install

Every package is a dsh bundle and ships a cordis.patch.yml. With the dsh CLI:

dsh plugin --profile my-agent add @amaster.ai/dsh-a2a @amaster.ai/dsh-storage @amaster.ai/dsh-langfuse
dsh --profile my-agent

For local development from this checkout, use a --patch overlay instead (no packaging needed):

# dev.patch.yml
- insert:
    - id: langfuse
      name: file:///absolute/path/to/dsh-plugins/packages/dsh-langfuse
dsh --profile my-agent --patch dev.patch.yml

Configuration

All plugins are disabled by default and configured through the standard dsh plugin config layer (Schemastery-validated, hot-reloaded). Example profile cordis.patch.yml snippet:

- insert:
    - id: langfuse
      name: '@amaster.ai/dsh-langfuse'
      config:
        enabled: true
        publicKey: pk-lf-...
        secretKey: sk-lf-...
        baseUrl: https://cloud.langfuse.com
    - id: storage-mirror
      name: '@amaster.ai/dsh-storage'
      config:
        enabled: true
        database:
          enabled: true
          provider: mysql   # mysql | postgresql | sqlite | sqlserver
          url: mysql://user:pass@host:3306/agent
    - id: a2a
      name: '@amaster.ai/dsh-a2a'
      config:
        enabled: true
        host: 127.0.0.1   # no auth built in — keep loopback or front with a proxy
        port: 41241
        cwd: /srv/agent-workspaces
        taskStore: redis  # memory | filesystem | redis | gcs — A2A task state only
        filesystem:
          root: /srv/dsh/a2a-tasks
        redis:
          url: redis://127.0.0.1:6379
        gcs:
          bucket: my-agent-archives
    - id: policy
      name: '@amaster.ai/dsh-policy'
      config:
        enabled: true
        rules:
          - tool: bash
            decision: deny
            commandPrefix: npm
            priority: 200
            message: 'npm is not allowed. Use bun instead.'
          - tool: '*'
            decision: allow
            priority: 20

Data model

dsh-storage's relational shape matches the source project's ai_messages / ai_chat_histories tables, so existing data stays compatible (one deviation: no user_id column — tenancy rides on session_id). It requires Prisma 7 peer packages at runtime: @prisma/client plus the driver adapter for your database (@prisma/adapter-mariadb for MySQL, @prisma/adapter-pg for PostgreSQL, @prisma/adapter-libsql for SQLite, @prisma/adapter-mssql for SQL Server). The PrismaClient is pre-generated per provider and shipped in the package — no `prisma generate` step. Create or upgrade the tables with the shipped schema variant:

npx prisma db push --schema node_modules/@amaster.ai/dsh-storage/prisma/schema.mysql.prisma --url "mysql://user:pass@host:3306/agent"
# schema.postgresql.prisma / schema.sqlite.prisma / schema.sqlserver.prisma work the same way

SQL Server note: Prisma's sqlserver connector has no Json type, so its variant maps the JSON columns to text — the backend serializes them on write automatically (derived from provider: sqlserver; SQL Server's ISJSON / JSON_VALUE still query the text as JSON).

  • `ai_messages` — user/model rows with thoughts, tokens, tool_calls, agent_id, metadata JSON columns and soft-delete; tool results update the matching model row's tool_calls.
  • `ai_chat_histories` — per-session rollup (message count, total tokens, first/last message timestamps).

The logical message id rides in metadata.id; message rows use a deterministic hash of (session_id, message id) as their primary key, so re-projected events upsert in place rather than duplicate — on every connector (the source project's metadata.id JSON-path lookup only works on PostgreSQL/MySQL). Session rows are matched by session_id and keep their cuid primary keys — the per-session serialization chain makes the find-then-write safe, and rows from the early scaffold (or the source project) are continued, never duplicated. Upgrade note: the early scaffold wrote messages with cuid keys; if you ran it, dedupe those by metadata.id before enabling this version.

Native inbox mode is opt-in and uses the official DSH APIs; it is tested with the unmodified 0.2.1-rc.3 npm runtime. See native inbox execution for queueing, steering, pause/recovery semantics and the runtime integration checks.

Opt into inbox: { enabled: true, shutdown: retain-pending } to retain unclaimed A2A steering and future turns across graceful host restarts. Retain both the session persistence and TaskStore storage; hosts still discover and wake eligible work. Explicit cancellation and context clearing remain terminal. See the shutdown contract.

A2A task snapshots are separate from the full conversation log: dsh-a2a ships pluggable TaskStore backends — in-memory (default), filesystem (private atomic JSON snapshots), Redis (task JSON + TTL), and GCS (gzipped task JSON). The snapshots retain A2A history and artifacts at task-state transitions; dsh-storage separately records the full conversation. Streamed text deltas stay in process until the next state change, so token-rate events never reach Redis or GCS. Redis and GCS keys are scoped to the A2A tenant and user; older unscoped records require migration or expiry.

Security

dsh ships no authentication or authorization. dsh-a2a binds 127.0.0.1 by default; if you expose it, put an authenticated reverse proxy in front and treat every agent as running with the host process's OS privileges. Multi-tenant deployments need per-tenant isolation (containers) on top.

Repository layout

packages/
├── dsh-a2a/        # A2A protocol server plugin
├── dsh-storage/    # session storage mirror plugin (+ prisma schema)
├── dsh-langfuse/   # Langfuse observability plugin
└── dsh-policy/     # declarative tool-call policy plugin

Development

pnpm install
pnpm build        # tsc per package
pnpm typecheck
pnpm test         # vitest (packages with a test script)

Current limitations

  • All plugins are disabled by default; enable and configure each explicitly in the profile.
  • dsh-a2a retains no event replay for subscriptions: SubscribeToTask opens with the current task snapshot and follows the live bus only. Resuming a dsh session after restart requires the optional sessionPersistence service.
  • dsh-a2a GCS store: workspace archiving (archiveWorkspace) shells out to tar and is not wired to the task lifecycle yet.

License

MIT