Skip to content

[FEATURE] Add support for DeepSeek Harness as an agent runtime #3194

Closed as not planned
Closed as not planned

Description

@Jacob953

Continued in the community repository

Following the maintainer's guidance in kagent#3195, this integration has moved to kagent-dev/byo-ext#2. Closing this core feature request because the work will continue as a community BYO integration. The community PR is still open and has not been merged. The original proposal below is retained as historical context.


📋 Prerequisites

📝 Feature Summary

Support DeepSeek Harness (DSH) as a kagent-managed agent through a maintained BYO integration or a native runtime adapter.

❓ Problem Statement / Motivation

DSH users should be able to keep its execution loop, plugins, and conversation state while using kagent for lifecycle management and access through the existing API and UI.

kagent 1.x alpha supports kagent, codex, claude, and byo runtimes. A BYO container must implement kagent's A2A gRPC service and readiness contract, so a DSH deployment still needs a protocol bridge. Using a DeepSeek model with another runtime does not provide DSH's execution behavior.

💡 Proposed Solution

Evaluate a pinned DSH version, then choose between a documented BYO integration and a native adapter. The evaluation should cover:

  • Mapping prompts, assistant output, tool events, and completion or failure to A2A tasks.
  • Applying model configuration, credential handling, workspace paths, and MCP bindings.
  • Canceling a turn and continuing the same conversation afterward.
  • Preserving the required DSH state across Actor suspension, restoration, and replacement.

DSH's ACP interface supports session creation and resumption, MCP attachment, cancellation, and permission requests. It emits semantic updates rather than raw provider deltas and does not support transcript replay. Output granularity and history ownership need an explicit mapping.

The SDK exposes subprocess control and event subscriptions, but currently lacks mid-turn cancellation and an implemented interactive approval flow. Its run() result is the last committed assistant response in an activity interval, not necessarily a response to one prompt. Protocol selection should account for these limits.

A native adapter should reuse kagent's shared runtime event model and A2A executor. API changes can follow agreement on the adapter's scope.

Validation should include consecutive turns, tool success and failure, cancellation followed by another turn, and conversation continuity after suspend/resume. If approvals are included, test allow, reject, and cancellation while awaiting a decision. Document any unsupported capabilities.

🔄 Alternatives Considered

  • Run DSH independently, with separate lifecycle and conversation management.
  • Build a custom BYO bridge and maintain its protocol mapping and version compatibility locally.
  • Use an existing kagent runtime with a DeepSeek model when DSH's execution loop and plugins are not required.

🎯 Affected Service(s)

Multiple services / System-wide

📚 Additional Context

This request has not been validated with a working integration. DSH's README warns that its preview can introduce breaking changes, so support needs pinned versions and an upgrade policy.

Maintainer feedback is requested on whether DSH integration fits the project's scope, whether BYO or a native adapter is preferred, which capabilities are required initially, and whether a separate Enhancement Proposal is needed.

🙋 Are you willing to contribute?

  • I am willing to submit a PR for this feature

Activity

  1. added theissue type on Oct 14, 2026
  2. foxj77 commented on Oct 17, 2026

    @foxj77

    I've been looking into this as well and ran a spike against a real DSH process to get evidence for the BYO vs native question. @Jacob953, you mentioned you're willing to submit a PR. Happy to coordinate so we don't duplicate work.

    Setup: @deepseek-ai/dsh@0.2.1-alpha.5 (commit 1517a4db), driven from Go over ACP (dsh --profile acp). Model calls went to a local Anthropic-compatible mock through DEEPSEEK_BASE_URL, including kagent's own mockllm unmodified. Run on macOS. Linux/pod behaviour is not tested yet.

    What works

    Result
    Multi-turn with tool calls ✅
    Cancel, then another turn ✅ cancelled in ~6 ms; a running bash tool is killed; the next prompt works
    Suspend/resume across process restart ✅ via session/resume, including after SIGKILL. Requires the workspace at the same real path (symlinks are fine); otherwise it fails cleanly with -32602
    Streamable HTTP MCP ✅ tools appear as mcp__<server>__<tool>, auth headers pass through. MCP servers must be re-sent on every resume
    Per-call token usage ✅ not over ACP, but recoverable from DSH's session log (compression: none): input/output/cache tokens on every call. No reasoning-token count
    Approvals (allow / reject / cancel while waiting) ✅ for bash sandbox escalation

    Gaps

    • No incremental output. ACP updates are built from completed assistant messages, so nothing reaches the client until each model response is done. Codex and Claude stream deltas.
    • No approval for MCP tools. MCP calls never raise session/request_permission, so requireApproval can't be honoured. A pending approval also doesn't survive a process restart. I'd expect the harness to report Approvals: false.
    • Defaults that need overriding. Stock profiles attach the session log (dsh_session_log, up to 8 MiB) and a plugin inventory to every model request, including to a custom DEEPSEEK_BASE_URL. Telemetry exports to DeepSeek unless DSH_TELEMETRY_DISABLED is set. A small profile overlay turns all of this off; I verified it on the wire.
    • The prompt response arrives ~1 ms before the turn is persisted. An adapter needs to wait for the turn's end record before reporting completion, or a crash in that window drops a reply the user already saw.
    • Pinning. The npm package uses tilde ranges for some runtime deps, so an image needs a lockfile or the single-file executable.

    Proposal

    1. ACP, not the SDK profile. The SDK has no mid-turn cancel and no working approvals.
    2. BYO first. An image built on kagent's public go/adk/pkg/app and go/harness/runtime/a2a gets the shared executor (cancellation, HITL parking, continuation, tracing) with no API change. The native-only work is controller-side: compiler, capability record, images, Helm, CI.
    3. Native later, if wanted, as an experimental, non-release-blocking harness in separate PRs, following the Codex/Claude precedent.

    Questions for maintainers:

    • Is BYO-first acceptable, and would a native DeepSeekHarness be welcome later as experimental?
    • Is v1 OK without incremental streaming and without MCP requireApproval, documented as unsupported?
    • For the model, reuse Anthropic with a base-URL override for now, and propose a DeepSeek provider separately?
    • Does this need an Enhancement Proposal?

    I've opened discussions upstream for the streaming and upload-default gaps: . I'm happy to share the spike code and captured transcripts if useful.

  3. Jacob953 commented on Oct 17, 2026

    @Jacob953
    Author

    Thanks for sharing the spike and offering to coordinate. The DSH integration has moved to the community repo following the maintainers’ guidance: proposal and PR.

    The adapter already implements MCP requireApproval through a proxy that holds calls before dispatch and persists approval state in Actor DATA. We’ve verified approval restoration after Worker replacement and continuation from settled forks in a real cluster. Native ACP permissions still require the original process, so that limitation remains, but Approvals: false would understate the adapter’s capabilities.

    We currently pin DSH 0.2.0-rc.2, while your spike uses 0.2.1-alpha.5. We also wait for session/close and its persistence flush before completing the task, disable telemetry, and build with an npm lockfile. Incremental output remains a gap.

    Your per-call usage findings are particularly useful—we’ve now confirmed those records in our pinned version too, but haven’t connected them to kagent telemetry yet. Would you be interested in coordinating on usage reporting or compatibility with the newer DSH version? Your spike code and captured transcripts would be helpful.

  4. foxj77 commented on Oct 17, 2026

    @foxj77

    Thanks @Jacob953, and thanks for pointing me to byo-ext. I hadn't seen #3195 or the move.

    You're right about approvals. I was only looking at what DSH exposes natively. Holding MCP calls in a proxy before dispatch, with the decision persisted in Actor DATA, is a better answer than Approvals: false. I've corrected that in the write-up.

    I'm not going to be able to take on work in the PR myself, but I'm happy to share everything from the spike in case it's useful for yours. I'll ping you an invite to the code.

    It's throwaway evidence code, not something to merge: 0.2.1-alpha.5, DSH's llm-deepseek provider, macOS, mock model servers only. It includes the probe code, ACP transcripts (multi-turn, cancel during a stream and a tool, resume after SIGKILL, MCP, the four permission cases), raw session logs, and a findings doc.

    A few things that may help directly:

    Usage mapping. This is how the spike maps the session log onto runtime.ModelCall:

    runtime.ModelCall Source
    Provider, ResponseModel assistant/message.data.message.source.{provider,model}
    RequestModel request/context.data.model
    OutputTokens, CacheReadTokens, CacheWriteTokens data.usage.*
    StopReason the finish chunk in data.stream (stop / tool-calls / max-tokens)
    Start / End step/start.time for the same turn/step / assistant/message.time
    Canceled + UsagePartial data.interrupted: true with no usage (a cancelled call has no usage)
    ReasoningOutputTokens, ResponseID, RequestID not available on the llm-deepseek path

    One caveat. On the llm-deepseek (Anthropic wire) path, inputTokens excludes cache tokens, so kagent's InputTokens needs cacheReadTokens + cacheWriteTokens added back. byo-ext uses llm-pi-ai, which may normalise differently. If its input already includes cached tokens, the same rule would double-count, so it's worth checking totalTokens against the parts on a record from your pinned version.

    Newer DSH versions. A session created by 0.2.0-rc.2 resumes under 0.2.1-alpha.5, and the reverse works too, on a shared DSH_HOME with raw JSONL. Recall works, there's still one session.v4.jsonl generation, and no migration is needed. (npm's latest is rc.2, which sorts below 0.2.1-alpha.5, so "newer" means the alpha line.) I didn't run byo-ext itself against alpha.5.

    Durability. In my runs, the session/prompt response arrived about 1 ms before that turn's turn/end was on disk, and a SIGKILL in that window dropped a reply the client had already seen. Your session/close flush covers this. If closing every task ever becomes a cost, waiting for the turn's turn/end record took about 1.5 ms in my measurements and keeps the session open.

    Good luck with the PR and shout if I can be of any help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions