跳到主要内容

dsh-call-agent

已验证

dsh-call-agent · v1.0.0 · MIT

DSH Native Cross-Session Collaboration, In-Process Agent Call, and Public Blackboard Plugin

安装

dsh plugin add dsh-call-agent

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

标签

作者

说明文档

dsh-call-agent

Native In-Process Cross-Session IPC & Workspace Shared Blackboard Primitive for DeepSeek Harness (DSH)

License: MIT ADR Architecture Node.js Version Cordis TypeScript Strict DSH Native Plugin

English | 简体中文


💡 Overview & Ecological Positioning (TL;DR)

dsh-call-agent is the native in-process cross-session communication pipeline (IPC) and workspace shared blackboard primitive designed for DeepSeek Harness (DSH).

Driven directly by Cordis microkernel dependency injection, dsh-call-agent provides strict 1:1 unicast call dispatch and a zero-wakeup public blackboard across concurrent DSH sessions. It resolves context fragmentation across autonomous sessions while architecturally preventing token explosion and execution disruption caused by uncontrolled broadcast storms.


🚀 Quick Start & Installation

DSH employs a Profile-based plugin management architecture. dsh-call-agent declares a standard dsh.bundle.patch manifest, allowing DSH to automatically reconcile it as a Profile Bundle and mount its Cordis composition layer upon installation.

1. Installation

Option A: Install from npm (Recommended)

# Install to the target profile (using the default 'web' profile as an example)
dsh plugin --profile web add dsh-call-agent

Option B: Install from GitHub Repository

# Direct Git repository install
dsh plugin --profile web add git+https://github.com/popu2do/dsh-call-agent.git

2. Verify Installed Plugins

# Verify active plugins in the target profile (the --profile argument is required)
dsh plugin --profile web list

3. Uninstall

dsh plugin --profile web remove dsh-call-agent

4. Configuration & Custom Overrides

The plugin provides production-ready defaults (300ms atomic debounce, 200 posts capacity, Web slash command enabled) and works immediately after installation with zero manual configuration required.

If tuning is required, add a property override block to ~/.dsh/profiles/web/cordis.patch.yml (do NOT duplicate - insert:):

# ~/.dsh/profiles/web/cordis.patch.yml (Optional configuration override)
- id: dsh-call-agent
  config:
    debounceMs: 500        # Adjust atomic disk debounce interval to 500ms
    maxCapacity: 500       # Expand blackboard FIFO cache to 500 entries

⚠️ Key CLI Invariants & Guardrails:

  1. Option Placement: --profile must be placed after the plugin subcommand (e.g., dsh plugin --profile web <args>). Specifying dsh --profile web plugin ... fails because Commander consumes it at root level and triggers argument isolation barriers.
  2. List Requires Profile: Running dsh plugin list without --profile will fail. Always use dsh plugin --profile web list.
  3. Avoid Duplicate Mount Anti-Pattern: Do not manually paste - insert: blocks into your profile's cordis.patch.yml. DSH reconciles and loads the bundle patch automatically upon installation.

🧩 Ecosystem Comparison & Decision Guide

In the DSH multi-agent ecosystem, dsh-call-agent, AgentTeams, and subagent serve distinct, complementary roles:

Dimension dsh-call-agent (Micro IPC & Blackboard) AgentTeams (Macro Workflow Orchestration) subagent (Vertical Task Delegation)
Ecosystem Role Low-level peer-to-peer IPC & shared fact state Structured team orchestration & DAG task scheduler Scoped ephemeral task execution
Topology Horizontal Peer-to-Peer, workspace-shared blackboard Captain-Workers hierarchy, Directed Acyclic Graph (DAG) Parent-Child tree hierarchy
Communication Native unicast (steer/followup) + Pull blackboard Structured asynchronous mailbox + round scheduling Parent-to-child input, child-to-parent output
Collaboration In-process direct memory bus, Two-Phase collaboration Quality-gate contracts (acceptance, verify, findings) Isolated turn/context execution
Wake-up Model Strict targeted wake-up; blackboard post is 100% passive Scheduler-driven ready task activation Synchronous block or async completion notice
Primary Use Cases Inter-session directive passing, shared test milestones Multi-agent collaborative delivery, full-lifecycle gates Focused code exploration, isolated builds, research

Decision Guide:

  • Scenario 1: When requiring multi-agent role division, formal quality review gates, and automated DAG scheduling ➔ Use AgentTeams.
  • Scenario 2: When independent, top-level concurrent sessions need to pass directives or share workspace facts and milestones ➔ Use dsh-call-agent.
  • Scenario 3: When running complex multi-agent teams that produce large artifacts (code diffs, test logs) ➔ Combine AgentTeams and dsh-call-agent (agents post bulky outputs to the blackboard and communicate compact postId references).
  • Scenario 4: When an agent needs to perform isolated, non-recurrent exploration without context pollution ➔ Use subagent.

💡 Core Architecture Philosophy

┌────────────────────────────────────────────────────────────────────────┐
│                      DeepSeek Harness Host Process                     │
│                                                                        │
│   ┌───────────────────────┐            ┌──────────────────────────┐   │
│   │   Session A (Caller)  │            │   Session B (Receiver)   │   │
│   └──────────┬────────────┘            └─────────────▲────────────┘   │
│              │                                       │                │
│              │ [Phase 1] board_post(bulky payload)   │                │
│              │ (returns compact postId, zero-wakeup) │                │
│              ▼                                       │                │
│   ┌─────────────────────────────────────┐            │                │
│   │    Shared Blackboard (BoardStore)   │            │                │
│   │    - In-memory cache / 300ms flush  │            │                │
│   │    - Isolated to current workspace  │            │ [Phase 2 (opt)]│
│   └─────────────────────────────────────┘            │ board_list     │
│              │                                       │ (fetch full)   │
│              │ [Phase 2] session_call                │                │
│              │ - target_session_id                   │                │
│              │ - context_post_ids: [postId]          │                │
│              │ - concise directive (<4000 chars)     │                │
│              └───────────────────────────────────────┘                │
│                 Adaptive dispatch: steer (running) / followup (idle)  │
└────────────────────────────────────────────────────────────────────────┘
  1. Separation of Concerns (Pull vs. Push):
    • Pull Domain (Public Blackboard): Hosts large-scale shared facts, build outputs, audit logs, and test results. Operates on a pure pull model; posting never interrupts or wakes other sessions.
    • Push Domain (In-Process Unicast): Carries targeted, actionable directives. Operates on strict 1:1 unicast, delivering directly to the specified recipient.
  2. Zero Passive Wake-up Side Effects:
    • Rejects broadcast primitives (*, all), eliminating unexpected interruptions and token cascading loops.
    • Post-and-forget for publishers; inspect-on-demand for consumers.
  3. Pure In-Process Native Injection:
    • Resolves target agent instances via ctx.agents.get(sessionId) in-memory.
    • Injects authentic MessageSource (kind: 'plugin', form: 'notice'), eliminating external HTTP daemons and pseudo RFC-822 text header wrapping.
  4. Adaptive Two-State Dispatch:
    • Targets in running status receive non-blocking steering via target.steer(message).
    • Targets in idle status are prompted with a new turn via target.followup(message).
  5. Physical Workspace Isolation by Default:
    • Applies consistent path normalization to keep session discovery and blackboard data strictly confined to the active project workspace.

🔄 Two-Phase Collaboration Pattern (Post-then-Call)

LLM context windows are constrained resources. In multi-agent environments, transmitting multi-file diffs, full build logs, or exhaustive test outputs directly inside message parameters causes rapid prompt bloat and risks exceeding message bounds.

dsh-call-agent establishes the Two-Phase Collaboration Pattern (Post-then-Call):

Phase 1: Post Bulky Context (Post)

The caller publishes large context to the shared blackboard using board_post, receiving a compact, unique postId:

// Tool Call: board_post
{
  "topic": "task:security-audit",
  "content": "# Security Audit Report\n\n- Files Checked: 128\n- Vulnerabilities: 0\n- Status: All parameter fuses and prefix disambiguation verified...",
  "tags": ["security", "audit", "completed"]
}
// Return value: postId = "post-1788520800000-xyz987"

Phase 2: Targeted Concise Call (Call)

The caller invokes session_call with a concise, actionable directive, referencing the stored payload via context_post_ids:

// Tool Call: session_call
{
  "target_session_id": "session-be7d7578b0fe",
  "call_type": "task_dispatch",
  "message": "Security audit verified. Please proceed with release artifact generation.",
  "context_post_ids": ["post-1788520800000-xyz987"]
}

Recipient: Pull on Demand (Pull)

The recipient receives the notification with clear instructions. When needed, it retrieves the full context via board_list:

// Tool Call: board_list
{
  "id": "post-1788520800000-xyz987"
}

📐 Architecture & Interaction Flows

1. Strict 1:1 Unicast Call & Adaptive Dispatch (session_call)

sequenceDiagram
    autonumber
    actor Caller as Caller Agent
    participant CallTool as session_call Tool
    participant Safety as Safety Fuses
    participant Agents as DSH agents Registry
    actor Target as Target Agent

    Caller->>CallTool: session_call(target_session_id, message, call_type, context_post_ids)
    CallTool->>Safety: Validate inputs (Wildcard Check / Self-call Check / Length Check)
    alt Validation Failed (Broadcast or Self-loop detected)
        Safety-->>Caller: Reject with safety fuse error
    end
    CallTool->>Agents: list() Query active candidate sessions
    CallTool->>CallTool: Resolve session ID / unique prefix (>= 8 chars)
    alt Multiple sessions match prefix (Ambiguous)
        CallTool-->>Caller: Throw Ambiguity Error (List candidate sessions)
    end
    CallTool->>Target: Inspect live status
    alt target.status === 'running'
        CallTool->>Target: target.steer(message) [In-flight steering channel]
    else target.status === 'idle'
        CallTool->>Target: target.followup(message) [New turn wake-up channel]
    end
    Target-->>CallTool: Native context injected (source.kind = 'plugin', form = 'notice')
    CallTool-->>Caller: Structured result (deliveryMode: 'steer' | 'followup')

2. Pull-Based Blackboard Pub/Sub with Atomic Persistence (board_post, board_list)

sequenceDiagram
    autonumber
    actor Publisher as Publisher Agent
    participant Board as AtomicBoardStore
    participant Disk as Persistent Disk (board.json)
    actor Subscriber as Subscriber Agent

    Publisher->>Board: board_post(topic, content, tags, ttl)
    Board->>Board: Store in memory Map, assign postId, tag workspace
    Board->>Board: Schedule / Reset debounce timer (default: 300ms)
    Board-->>Publisher: Return immediate confirmation (Zero wakeup side effects)
    Note over Board,Disk: After debounceMs trailing delay (default 300ms)
    Board->>Disk: Atomic write to board.json.tmp -> rename to board.json
    Board->>Disk: Rotate snapshot to board.json.bak
    
    Subscriber->>Board: board_list(topic, callerWorkspace, titles_only)
    Board->>Board: Filter by workspace scope + evict expired TTL records
    Board-->>Subscriber: Return structured posts (supports titles_only)

3. Workspace-Scoped Session Discovery (session_query)

sequenceDiagram
    autonumber
    actor Explorer as Explorer Agent
    participant QueryTool as session_query Tool
    participant Host as DSH Engine / Agents Service

    Explorer->>QueryTool: session_query(query, running_only, cross_workspace)
    QueryTool->>Host: Inspect active session descriptors & cwd paths
    QueryTool->>QueryTool: Normalize paths & filter by caller workspace
    alt cross_workspace === false (Default)
        QueryTool->>QueryTool: Retain only current workspace sessions
    else cross_workspace === true
        QueryTool->>QueryTool: Retain all workspace sessions (Cross-repo)
    end
    QueryTool->>QueryTool: Normalize status strictly to 'running' | 'idle'
    QueryTool-->>Explorer: Return session list [{ sessionId, title, status, cwd }]

🛠️ Tool & Command Reference

Summary Matrix

Name Kind Mode Scope Description
/dsh-call-agent Slash Command Dual Local / Global Interactive command in Web GUI: empty args displays board digest; arguments send unicast call.
board_post Native Tool Pull Local / Global Publish milestone or task context to public blackboard (Zero passive wakeups).
board_list Native Tool Pull Local-first Query blackboard entries. Supports titles_only mode (saves 85%+ Tokens) and cross_workspace.
board_clear Native Tool Pull Controlled Dismiss (soft-archive for audit trail) or purge (hard-delete) blackboard entries.
session_call Native Tool Push Strict 1:1 Send unicast call to target session. Dispatches via steer (running) or followup (idle).
session_query Native Tool Read-only Local-first Discover active/idle sessions. Status normalized strictly to running or idle.

Detailed Tool Specifications

1. session_call — Strict 1:1 In-Process Unicast Call

Directly injects a structured directive into the target agent session without fake human impersonation.

Parameters:

  • target_session_id (string, required): Full session ID or unique prefix of at least 8 characters. Wildcards (*, all, broadcast) are strictly forbidden.
  • message (string, required): Concise, clean task instruction, report, or handoff content (max 4,000 characters).
  • call_type (string, optional, default: 'task_dispatch'): Intent type: 'task_dispatch' (task assignment), 'task_report' (status report), or 'notice' (general notification).
  • context_post_ids (string[], optional): Array of referenced blackboard post IDs for large context lookups.

Tool Call Example:

{
  "name": "session_call",
  "arguments": {
    "target_session_id": "session-be7d7578b0fe",
    "call_type": "task_dispatch",
    "message": "Please review TypeScript definitions under types/index.d.ts and verify strict export conformance.",
    "context_post_ids": ["post-1788520800000-xyz987"]
  }
}

Output Schema:

{
  "success": true,
  "targetSessionId": "session-be7d7578b0fe",
  "targetTitle": "TypeScript Reviewer",
  "targetStatus": "idle",
  "deliveryMode": "followup",
  "callType": "task_dispatch",
  "callerSessionId": "session-dc5d61e712ee",
  "contextPostIds": ["post-1788520800000-xyz987"],
  "message": "Successfully dispatched task_dispatch to target session [session-be7d7578b0fe] via followup."
}

2. session_query — Workspace-Scoped Session Discovery

Explores accessible sessions in the local workspace or across projects.

Parameters:

  • query (string, optional): Fuzzy search keyword matching Session ID or Title.
  • running_only (boolean, optional, default: false): When true, filters only sessions currently processing a turn.
  • cross_workspace (boolean, optional, default: false): When true, scans all workspaces across repositories.
  • top_level_only (boolean, optional, default: true): When true, excludes child subagents and anonymous sessions.
  • limit (integer, optional, default: 50, min: 1, max: 100): Maximum results to return.

Tool Call Example:

{
  "name": "session_query",
  "arguments": {
    "cross_workspace": false,
    "running_only": false,
    "limit": 10
  }
}

Output Schema:

{
  "success": true,
  "count": 2,
  "scope": "dsh-call-agent",
  "sessions": [
    {
      "sessionId": "session-dc5d61e712ee",
      "title": "Release Captain",
      "status": "running",
      "cwd": "D:/Projects/dsh-call-agent"
    },
    {
      "sessionId": "session-be7d7578b0fe",
      "title": "Documentation Lead",
      "status": "idle",
      "cwd": "D:/Projects/dsh-call-agent"
    }
  ]
}

3. board_post — Post to Public Blackboard

Publishes shared facts, build milestones, or task contexts onto the public board. Zero passive wakeup side effects.

Parameters:

  • topic (string, required): Topic category, e.g., 'task:audit', 'build:artifact', 'spec:api'.
  • content (string, required): Body content in Markdown, plaintext, or JSON string (up to 64KB).
  • tags (string[], optional): Array of search tags, e.g., ['p0', 'ready-for-review'].
  • ttl (integer, optional, default: 3600, max: 86400): Time-to-live in seconds.
  • metadata (object, optional): Structured metadata key-value pairs.

Tool Call Example:

{
  "name": "board_post",
  "arguments": {
    "topic": "task:audit",
    "content": "Security audit completed for v1.0.0. All credential leaks resolved. Zero vulnerabilities identified.",
    "tags": ["security", "audit", "passed"],
    "ttl": 7200,
    "metadata": {
      "auditor": "security-reviewer",
      "passed": true
    }
  }
}

Output Schema:

{
  "success": true,
  "postId": "post-1788520800000-xyz987",
  "topic": "task:audit",
  "authorSessionId": "session-a96887cc5d06",
  "createdAt": "2026-09-04T12:00:00.000Z",
  "expiresAt": "2026-09-04T14:00:00.000Z",
  "scope": "dsh-call-agent",
  "message": "[Board] Successfully published post (#post-1788520800000-xyz987). Pure pull model, zero passive wakeups."
}

4. board_list — Query Blackboard Announcements

Pulls active announcements from the blackboard.

Parameters:

  • topic (string, optional): Exact topic match (e.g., 'task:audit').
  • topic_prefix (string, optional): Prefix match (e.g., 'task:').
  • tag (string, optional): Search by specific tag.
  • active_only (boolean, optional, default: true): Exclude expired/dismissed posts.
  • cross_workspace (boolean, optional, default: false): Search across all workspace domains.
  • titles_only (boolean, optional, default: false): Token Optimization: Returns only metadata and titles without heavy body content (saves 85%+ Tokens).
  • limit (integer, optional, default: 20, max: 100): Maximum entries to return.

5. board_clear — Dismiss or Purge Blackboard Entries

Manages blackboard retention and lifecycle.

Parameters:

  • id (string, optional): Specific post ID to dismiss or purge.
  • topic (string, optional): Topic category to batch-clean (when id is not specified).
  • mode (string, optional, enum: ['dismiss', 'purge'], default: 'dismiss'):
    • 'dismiss': Soft-delete marking status as archived (preserves audit trail).
    • 'purge': Hard-delete physically removing the entry.

Web Slash Command: /dsh-call-agent

In the DSH Web GUI, users and operators can invoke /dsh-call-agent directly:

  1. Digest Mode (No Arguments):

    /dsh-call-agent
    

    Renders a concise, formatted summary of all active blackboard announcements in the current workspace.

  2. Dispatch Mode (With Arguments):

    /dsh-call-agent session-be7d7578b0fe Please proceed with Task #8 document verification.
    

    Directly unicasts the command to the target session in real time. The Web GUI presents a folded ContextInjectionRow notification.


⚙️ Configuration & Profile Composition

The plugin exports a standard Bundle Patch automatically mounted upon installation:

# cordis.patch.yml (Plugin Bundle Patch)
- insert:
    - id: dsh-call-agent
      name: dsh-call-agent
      config:
        enabled: true
        debounceMs: 300
        maxCapacity: 200

Configuration Options Schema

Option Type Default Description
enabled boolean true Whether to enable cross-session tools and blackboard store.
storagePath string (auto) Path to board.json file (defaults to plugin root or system storage).
debounceMs number 300 Trailing debounce interval (ms) for atomic disk writes.
maxCapacity number 200 Maximum active posts retained before FIFO eviction.
promptSectionOrder number 118 Ordering weight when injecting collaboration instructions into global system prompt.
slashCommand boolean true Whether to register the /dsh-call-agent command in the Web command registry.

📖 Architecture Decision Records (ADRs)

All core invariants, technical choices, and behavioral contracts are governed under standard Architecture Decision Records (ADRs):

👉 Browse Full Architecture Decision Records (docs/adrs/README.md)

ADR Title Status Core Value & Impact
ADR-0001 Separation of Concerns: Pull Board vs Push Unicast Accepted Eliminates token cascading loops and chaotic uncoordinated session wakeups.
ADR-0002 Built-in Blackboard State Store (Zero External Dep) Accepted In-memory store with pure pull semantics, zero external database dependencies.
ADR-0003 Workspace-Scoped Isolation by Default Accepted Protects multi-repository projects from context cross-contamination.
ADR-0004 Atomic Debounced Persistence & Backup Recovery Accepted 300ms debounce + temp file swap + .bak mirror crash recovery.
ADR-0005 English Metadata & Two-State Status Protocol Accepted Strict convergence of runtime states to running | idle.
ADR-0006 Pure DSH Native In-Process Context Injection Accepted In-memory ctx.agents.get(), native MessageSource, dual dispatch.
ADR-0007 Web Slash Command & Visual Trajectory Folding Accepted /dsh-call-agent slash command + low-profile collapsed GUI folding.
ADR-0008 Zero-Pollution Global Profile Mounting & Lifecycle Accepted Declarative cordis.patch.yml bundle mount + safe dispose flush.

🧪 Testing & Verification

The test suite runs on Node.js 20+ native test runner (node:test and node:assert/strict) with zero third-party dependencies:

# Run unit & integration test suite (32 native test cases)
npm test

# Run code check
npm run lint

# Full pre-flight verification
npm run verify

🤝 Community & Contributions

We welcome contributions and feedback from the community! Please consult our documents:


📄 License

This project is licensed under the MIT License.