hy-sde/dsh-graph--packages-graph-executor ↗★ 0

@hy-sde-org/dsh-graph-executor

智能体图子算子执行器适配器 负责智能体图的算子绑定与工作区租约管理,适合需要确定性执行子任务的场景。

包名
@hy-sde-org/dsh-graph-executor
兼容性
待验证
版本
0.2.0-rc.2
许可证
MIT
最近更新
2026年10月3日

安装

此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗

@hy-sde-org/dsh-graph-executor

English | 中文

Summary

dsh-graph-executor is the child-operator executor adapter of the Agent Graph. It implements the coordinator's AgentGraphExecutor surface over two injected seams: a GraphOperatorWorktreePool (acquire/release worktree leases for one repository) and a GraphOperatorChildRunner (one provider-backed child run per activation). The control store stays the durable authority — provisions and bindings are rows, and everything else is derived.

Provisioning is deterministic and idempotent: provisionOperator derives graph_operator_lease_ from the provision, so a retry adopts the same lease key, and pool.acquire is idempotent per key (process-local by design; the binding row is the durable hint a real pool consults after a restart). When no lease can be acquired the method returns undefined and the reconciler defers the work to a later drive.

Execution is serialized per operator (one child run at a time) and settles into exactly one terminal record per activation: the runner's summary is truncated to 16 KiB (truncateUtf8, … suffix) and emitted as an AgentGraphRecordSourceEvent (facets: ['message', 'terminal']) through recordSink; a failed run without a summary emits [operator failed] . A child failure never throws from runClaimedAgentGraphIntent — records are the observation channel.

This package contributes no tool, prompt, or plugin row — the stream-layer coordinator and the supervisor tools consume it.

Table of Contents

Use this package

import { GraphControlStore } from '@hy-sde-org/dsh-graph-control'
import { AgentGraphCoordinator } from '@hy-sde-org/dsh-graph-stream'
import { createGraphOperatorExecutor } from '@hy-sde-org/dsh-graph-executor'

const executor = createGraphOperatorExecutor({
  store,
  pool: worktreePool,       // GraphOperatorWorktreePool over the git worktree engine
  childRunner: childRunner, // GraphOperatorChildRunner over the subagent runtime
  recordSink: recordSink,   // commits AgentGraphRecordSourceEvent rows
  newId,
})

const coordinator = new AgentGraphCoordinator(graphId, {
  store,
  executor,
  recordSource,
  newId,
  maxNewActivations: 4,
})

Understand the implementation

Provision: lease key, binding, and the durable row

provisionKey(request) hashes { graphId, workId, provisionFingerprint } with stableHash32, so retries of the same provision reuse one lease key. provisionOperator then acquires the lease (or adopts it), persists bindOperatorWorktree({ graphId, workId, provisionId, leaseId, path, repoRoot, boundAt }), and finally commits the provision row through the store — the same revision-conditional, closure-blocked write the control store already owns. Acquire failure returns undefined; the binding row is never written without a lease. Re-binding the same provision with a different lease id is rejected (binding-conflict), so a provision owns exactly one worktree.

Run: admission, serialization, and settlement

runClaimedAgentGraphIntent queues the activation on a per-operator promise chain, so one operator never runs two children at once. Inside the queue it first evaluates admitExecution (post-serialization revision gate) and aborts when it returns cancelled; then it resolves the operator's binding — through the ${graphId}:${workId} index when the intent's readiness id names the provisioning work (dynamic operators), or through the provision's operatorId for operator-targeted work, which re-runs a provisioned operator — and starts the child with { sessionId, instructions, workspace: binding.path, runId, labels, abortSignal }. concurrencyHint optionally caps concurrently running child starts across operators.

After the child settles, one AgentGraphRecordSourceEvent is built (runtimeEventId from newId, seq 1, the claim's targetRunId, truncated summary) and handed to recordSink; the folded AgentGraphRecord is also returned. recordSink failure propagates — the terminal record is the commit point that stops the reconciler from re-dispatching the same claim.

Bindings in the control store

The control store gained one authoritative table, operator_bindings (row key provisionId), with a derived ${graphId}:${workId} index rebuilt at open. Methods: bindOperatorWorktree (idempotent same-lease rebind keeps the original boundAt; different-lease rebind throws binding-conflict), readOperatorBinding, readOperatorBindingByWork, listOperatorBindings(graphId?).

Further Exploration

Model Experience

No model-facing surface. The package is host-side machinery: it renders no prompt (the stream layer does), and the terminal summaries it records are what the supervisor tools present.

Known Limitations and Deferred Work

  • Lease idempotency is process-local: a real pool implementation adopts a previously leased worktree after a restart by matching listWorktrees; nothing here re-derives leases from the store binding (the binding is the durable hint, not the lease authority).
  • Worktrees intentionally survive terminal runs (Maka contract); the executor never releases a lease. Pool release is wired in for graph teardown by the host assembly.
  • recordSink failures propagate as execution failures — the reconciler reports them and the host retries; there is no crash-consistent terminal-event log yet.
  • runClaimedAgentGraphIntent observes the seam contract the dsh-graph-stream README documents (provisionOperator may return undefined); the AgentGraphExecutor type in dsh-graph-stream's src/types.ts still declares a non-optional provision result and is expected to line up on integration.