DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Graph Runtime — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins

dsh-graph-runtime

Graph Runtime

DeepSeek Harness 的图运行时功能:将 LangGraph 编译后的图注册为 DSH 工具,并提供由图驱动的路由代理。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add dsh-graph-runtime@0.2.0
README兼容性版本

兼容性与来源证明

Graph Runtime 以 dsh-graph-runtime 发布,当前版本为 0.2.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
any
发布来源
npm
Registry 更新时间
2026/9/17

版本

0.2.0stable
2026/9/17
0.1.0stable
2026/9/17

相关插件

正在加载相关插件…

最新版
0.2.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
95.2 kB
文件数
21
Surface
any
许可证
MIT
发布源
npm
GitHub
★ 1
周下载
0
最近提交
2026/9/17
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 agents-orchestration 分类下经过校验的插件。

Headless@deepseek-ai/dsh-headlessdsh one-shot bundle:基于 dsh-base 的直接核心 Agent/Session 运行器,不包含 Host、HTTP 或浏览器层Experimental Agent Team Web Profile@deepseek-ai/dsh-experimental-agent-team-web-profile用于 Agent Teams Remote 和 UI 插件的实验性 Web 配置层Subagent Codex@deepseek-ai/dsh-subagent-codex基于官方 app-server 协议的一次性 Codex 子代理提供程序Subagent Claude Code@deepseek-ai/dsh-subagent-claude-code基于官方 Agent SDK 的一次性 Claude Code 子代理提供方

README

dsh-graph-runtime

English | 中文

Graph runtime capabilities for the DeepSeek Harness (DSH), published as a standalone Cordis plugin/bundle.

Current capabilities:

  • Graph definition and auto-mounting: define an "extended StateGraph" with defineGraph — a graph factory plus a registration declaration (whether it becomes a DSH tool, whether it joins the registry) plus a tool-argument validation hook. Loading the module completes registration: at plugin startup the already-defined graphs auto-mount, and later definitions mount immediately; developers make no service calls at all. Tool name/description are auto-discovered (compile({ name, description }) or structural synthesis), compilation is lazy and memoized (the registration path has zero compile side effects), and parameter validation, cancellation forwarding, and result rendering are all owned by this plugin.
  • GraphRoutingAgent: a graph-driven routing agent. It hands the graphTools registry (optionally filtered) to the LLM and requires a tool to be chosen; the returned tool call goes through existence, JSON, schema, and author validate checks, retrying with the rejection reason on failure (default 3, configurable); once it passes, the corresponding graph executes. Every chosen-tool execution is wrapped by the graphTools/pre-execute / graphTools/post-execute waterfall extension points (gating, auditing, result transforms).

Installation and wiring

# After publishing
npm install dsh-graph-runtime
# Or from a local path (e.g. inside the yolo-agent repo)
npm install file:../dsh-graph-runtime

Wiring follows the same steps as any other DSH bundle, either or both:

  • Add one entry to the root composition cordis.yml (this package ships its own cordis.patch.yml; adding the package name to the web profile's dsh.profile.bundles auto-mounts it the same way):

    - id: graph-runtime
      name: dsh-graph-runtime
    

Usage

Graph authors only need defineGraph — defining is registering; no mount or service call is required:

// graphs/echo.ts
import { defineGraph } from 'dsh-graph-runtime'
import { Annotation, END, START, StateGraph } from '@langchain/langgraph'

const State = Annotation.Root({
  topic: Annotation<string>,
  log: Annotation<string[]>({
    reducer: (left, right) => [...left, ...right],
    default: () => [],
  }),
})

export const echoGraph = defineGraph({
  name: 'echo_graph',
  description: 'Echo the given topic.',
  build: () =>
    new StateGraph(State)
      .addNode('echo', async (state) => ({ log: [`seen:${state.topic}`] }))
      .addEdge(START, 'echo')
      .addEdge('echo', END),
  asTool: true, // Declared as a model-visible DSH tool; default false
  // asGraphTool: true, // Also listed in the graphTools registry for discovery; default true, can be omitted
  // validate: (input) => Boolean((input as { topic?: string }).topic), // Argument-validation hook; defaults to always passing
})

The only wiring requirement: a graph module must be imported by some bundle entry (a single barrel line import './graphs' suffices). At plugin apply, every already-defined graph auto-mounts, and later definitions mount immediately; a single graph failing to mount (duplicate name, invalid declaration) warns and is skipped without blocking startup.

Tools declared asTool: true register at the plugin's global layer: visible to every agent (including the default agent). For scope-private or runtime-constructed cases, use the imperative entries below.

GraphRoutingAgent

Trimmed from dsh's ReactLoopAgent to a single routing step: one routing round = the LLM picks a tool → validation → (optional retry) → the graph executes.

import { GraphRoutingAgent } from 'dsh-graph-runtime'

const router = new GraphRoutingAgent(ctx, {
  provider: 'deepseek',
  model: 'deepseek-chat',
  filter: { allow: ['echo_graph', 'search_graph'] }, // allow/deny, same as tools.restrict
  maxRetries: 3, // Maximum LLM re-calls after a failed validation; default 3
  // fallback: myFallbackTool, // Optional: overrides the built-in fallback tool
})

const outcome = await router.route({ input: 'echo hello for me' })
// outcome: { tool: 'echo_graph', args: {...}, result: <the graph's final state> }

Behavior details:

  • A tool must be chosen: dsh-llm's GenerateOptions has no toolChoice field, so the "required" semantics are enforced by the loop — when the model picks no tool (a plain-text reply) there is no retry; the fallback tool runs instead and the outcome is marked fallback: true. The default fallback is the built-in graph_routing_fallback (a no-op: empty input, returns {}); override it through fallback with a ToolDefinition or a GraphDefinition, and the overrider is responsible for keeping empty input {} valid under its schema (e.g. parameters: {}).
  • The validation chain (any failure retries with the reason): the tool exists in the (filtered) registry; the arguments are valid JSON; execution-time schema validation (ToolArgsError); the author's validate hook (GraphValidationError, with context.request available during routing for semantic rejection). A graph's own runtime failure is not a routing failure and propagates as-is.
  • Filtering: filter follows the same allow/deny semantics as tools.restrict (both may be given; they intersect); a list naming unknown tools or an empty result after filtering is a configuration error.
  • Exhausted retries end with the last failure reason.

Routing extension points

Routed executions do not pass through dsh's ctx.tools pipeline (the registry there is a separate surface), so the pipeline-shaped extension points live on the routing loop itself as cordis waterfall events: every chosen-tool attempt traverses graphTools/pre-execute before the graph runs and graphTools/post-execute after it settles. Audit logging, metrics, policy gating, and result transforms all hang off them:

// Gate before execution: a deny feeds the reason back to the model for a
// retry, exactly like a validate rejection.
ctx.on('graphTools/pre-execute', async (execution, next) => {
  if (disabledTools.has(execution.tool)) {
    return { kind: 'deny', reason: `"${execution.tool}" is disabled by policy` }
  }
  return next()
})

// Observe or reshape the settled outcome; fires on successes and failures alike.
ctx.on('graphTools/post-execute', async (execution, outcome, next) => {
  if (execution.tool === 'search_graph' && !('error' in outcome)) {
    return { kind: 'accept', result: redact(outcome.result) } // replace the returned value
  }
  return next()
})

Semantics:

  • execution carries tool / args / request (the original routing text) / signal; the same object reaches both events of one attempt.
  • Waterfall order: listeners run in registration order; next() delegates, and answering without next() vetoes the rest — the first decision wins.
  • deny (pre) and block (post) join the ordinary retry loop: the reason is fed back to the model and retries exhaust into the standard error. A block rejects any settled outcome — it can also convert a propagating graph error into a retried choice instead of an error.
  • accept keeps the settled outcome; with result it replaces the value returned to the caller (listeners still observed the original).
  • The fallback path (no tool chosen) traverses neither event; if you need hooks there, wrap your fallback tool's execute. A throwing listener propagates as-is. Listeners register with plain ctx.on like any cordis event; inside a listener, this is the agent's ctx.

Registration declaration

FieldMeaning
asToolWhether to register as a model-visible DSH tool (ctx.tools). Default false; the auto-mount path registers at the plugin's global layer (visible to all agents), the imperative mount path registers at the layer of the ctx passed in.
asGraphToolWhether to list in the graphTools registry for discovery (get/list, GraphRoutingAgent). Default true.

defineGraph fields

FieldMeaning
nameThe graph name, which becomes the registered tool name; globally unique; the reserved name run_code is rejected.
descriptionOptional. The model-facing tool description; defaults to the description written by compile({ description }) on the build() product (when the author compiled it), or a structural description synthesized from nodes and state keys.
buildGraph factory: returns an uncompiled builder (the plugin plain-compile()s it at first invocation, passing no options), or an author-compiled instance. Checkpointer and all compile options belong entirely to the author — for state memory, return builder.compile({ checkpointer: new MemorySaver() }).
validateOptional argument-validation hook: receives (input, context) before the graph runs; context.tool is the tool name, and when routed through GraphRoutingAgent context.request carries the original request text (absent on direct calls). Returning false or throwing rejects (a thrown message becomes the rejection reason); defaults to always passing. This enables "this request is not mine" semantic rejection, which the routing loop retries with the reason.
parametersOptional DSH ParameterSchemaSpec. When provided, the whole argument object becomes the graph input; when omitted, the tool exposes a single required input JSON parameter (its description is appended with the discovered state key names, but the value itself stays opaque). Model-visible graphs should always declare it — see the next section.
threadIdOptional thread key; forwarded as-is into the graph config's thread_id. Whether it produces state memory is decided by the graph's own checkpointer (the plugin manages none).
configurableOptional extra configurable keys forwarded as-is (thread_id is governed by threadId).
timeoutMsOptional cooperative timeout budget; the graph must respond to the cancellation signal and converge.

Parameter schema quality (required reading for model-visible graphs)

parameters is forwarded as-is as a DSH ParameterSchemaSpec and enforced before execution (out-of-range enums, type mismatches, and missing requireds are all stopped by ToolArgsError). For graphs a model will see, keep every parameter explicitly typed, concretely described, and fully enumerated:

defineGraph({
  name: 'greet_graph',
  build: () => buildGreetGraph(),
  parameters: {
    name: { type: 'string', required: true, description: 'The name to greet.' },
    style: {
      type: 'string',
      required: true,
      enum: ['formal', 'casual'],
      description: 'Greeting style.',
    },
    times: { type: 'integer', description: 'Repeat count.', default: 1 },
    tags: { type: 'array', items: { type: 'string' }, description: 'Extra tags.' },
  },
})

Supported capabilities: type is one of string / number / integer / boolean / null / array / object / json, unions use oneOf; every key may carry description / title / default / examples; enums use an enum matching the type (e.g. a string array), single-value constraints use const; nested objects use object + properties + additionalProperties, arrays use items; mark required keys individually with required: true.

Why nothing is derived automatically: langgraph drops Annotation type information at compile time, leaving only key names and aggregation semantics in the runtime structure — a schema with fabricated types or requireds would mislead the model into assembling arguments the validation layer then rejects, which is worse than an honest input. So the fallback without declared parameters is a single required input (json), whose description carries the discovered state keys (e.g. Expected state keys: topic, log (accumulated).); when asTool: true and no parameters are declared, the mount path logs a warn through ctx.logger to nudge the author.

Imperative entries (dynamic / low-level scenarios)

// A runtime-constructed graph: createGraphDefinition constructs without
// publishing (defineGraph auto-mounts, so an explicit mount while the
// plugin is active would double-register), paired with an explicit mount;
// ctx is both the fiber owner and the ctx.tools registration target.
const dynamicGraph = createGraphDefinition({
  name: 'dynamic_flow',
  build: () => buildDynamicGraph(),
  asTool: true,
})
const mounted = ctx.graphTools.mount(dynamicGraph, ctx)

// Discovery side: ctx.graphTools.get('echo_graph') / ctx.graphTools.list()

// Already holding a compiled graph, or only want a one-off conversion:
const entry = ctx.graphTools.register(compiledGraph, ctx)
const tool = ctx.graphTools.create(compiledGraph)

import { createGraphTool } from 'dsh-graph-runtime' also does the pure conversion directly, with the same effect. Passing a graph definition to register fails with an error pointing at mount — graph definitions carry their own registration declaration. defineGraph targets graph authors (declare-and-publish, auto-mount); createGraphDefinition targets runtime-dynamic scenarios (construction stays construction, mounting stays mounting).

Behavior contract

  • Defining is registering: defineGraph publishes the graph definition to a package-level static queue; at plugin apply the queue is taken over and drained, and later definitions mount immediately. A single graph failing to mount (duplicate name, invalid declaration) is skipped with a ctx.logger warning and never blocks startup; after the plugin disposes, defineGraph queues again and can remount with the next plugin load.
  • Registration is only registration: defineGraph/mount/register never call langgraph's compile(); an uncompiled builder is plain-compile()d exactly once at the tool's first real invocation and memoized (structural discovery only reads the builder's nodes/channels and likewise never compiles).
  • The checkpointer belongs to the graph: the plugin never injects or manages compile options; threadId is only a thread_id pass-through, and whether memory takes effect depends on the instance the author returns from build().
  • Each tool call is one graph.invoke; tool arguments pass DSH parameter-schema validation and the author's validate hook before entering the graph, and the caller's AbortSignal is forwarded as-is.
  • The graph's final state must be lossless JSON, or it is rejected with an explicit error; the tool result returns to the model as a pretty-printed JSON text block.
  • Interaction with ctx.tools happens only when asTool: true is declared: the auto-mount path registers at the plugin's global layer (visible to every agent including the default agent); imperative mount(definition, ctx) registers at the layer of the passed ctx (on an agent-scoped ctx, visible only to that agent, shadowing a same-named global tool). The graphTools registry is separate state: listed names are unique, unregister is idempotent, and entries leave automatically with the disposing fiber of the mounting path.
  • Limits of auto-discovery: Annotation type information and addNode descriptions are dropped when langgraph compiles, so a parameter schema cannot be derived automatically. Discovery degrades safely for a custom GraphInvocable missing runtime fields, but the name must be provided explicitly.