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)
💡 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:
- Option Placement:
--profilemust be placed after thepluginsubcommand (e.g.,dsh plugin --profile web <args>). Specifyingdsh --profile web plugin ...fails because Commander consumes it at root level and triggers argument isolation barriers.- List Requires Profile: Running
dsh plugin listwithout--profilewill fail. Always usedsh plugin --profile web list.- Avoid Duplicate Mount Anti-Pattern: Do not manually paste
- insert:blocks into your profile'scordis.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
AgentTeamsanddsh-call-agent(agents post bulky outputs to the blackboard and communicate compactpostIdreferences). - 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) │
└────────────────────────────────────────────────────────────────────────┘
- 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.
- 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.
- Rejects broadcast primitives (
- 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.
- Resolves target agent instances via
- Adaptive Two-State Dispatch:
- Targets in
runningstatus receive non-blocking steering viatarget.steer(message). - Targets in
idlestatus are prompted with a new turn viatarget.followup(message).
- Targets in
- 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): Whentrue, filters only sessions currently processing a turn.cross_workspace(boolean, optional, default:false): Whentrue, scans all workspaces across repositories.top_level_only(boolean, optional, default:true): Whentrue, 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 (whenidis not specified).mode(string, optional, enum:['dismiss', 'purge'], default:'dismiss'):'dismiss': Soft-delete marking status asarchived(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:
Digest Mode (No Arguments):
/dsh-call-agentRenders a concise, formatted summary of all active blackboard announcements in the current workspace.
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
ContextInjectionRownotification.
⚙️ 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:
- 📋 Contributing Guide: Development workflow and PR guidelines.
- 🛡️ Security Policy: Vulnerability disclosure procedure.
- 📝 Changelog: Version history following Keep a Changelog standards.
📄 License
This project is licensed under the MIT License.