@kasenri/dsh-orbit 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +220 -0
- package/cordis.patch.yml +9 -0
- package/lib/activation.js +110 -0
- package/lib/client.js +625 -0
- package/lib/decisions.js +167 -0
- package/lib/dsh-host.js +364 -0
- package/lib/evidence.js +149 -0
- package/lib/guard.js +157 -0
- package/lib/host.js +1 -0
- package/lib/index.js +138 -0
- package/lib/kernel.js +355 -0
- package/lib/pipeline-guard.js +75 -0
- package/lib/routes.js +52 -0
- package/lib/sanitize.js +39 -0
- package/lib/service.js +104 -0
- package/lib/settlement.js +33 -0
- package/lib/state-store.js +128 -0
- package/lib/supervisor.js +792 -0
- package/lib/tool.js +82 -0
- package/lib/types.js +19 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 KasenRi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @kasenri/dsh-orbit
|
|
2
|
+
|
|
3
|
+
Community plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH).
|
|
4
|
+
Not affiliated with or endorsed by DeepSeek.
|
|
5
|
+
|
|
6
|
+
**Orbit — Deterministic Engineering Orchestration for DeepSeek Harness**
|
|
7
|
+
|
|
8
|
+
Orbit is a deterministic engineering orchestration runtime for DSH, implemented
|
|
9
|
+
as a Cordis plugin:
|
|
10
|
+
|
|
11
|
+
- an `OrbitService` on `ctx.orbit`
|
|
12
|
+
- a model-facing `orbit_controller` tool (`cx_controller` remains a legacy alias)
|
|
13
|
+
- recoverable tool guards
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Goal
|
|
17
|
+
│
|
|
18
|
+
▼
|
|
19
|
+
OrbitService
|
|
20
|
+
└─ Deterministic Supervisor
|
|
21
|
+
├─ Commander (plan / step & final evaluation / strategy reconsider)
|
|
22
|
+
├─ Executor (one engineering step at a time)
|
|
23
|
+
└─ Smart Watchdog (runtime diagnosis and recovery)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Every child role runs on DSH's native `ctx.subagents` service; durable state
|
|
27
|
+
lives in `<project>/.cx/state.json`.
|
|
28
|
+
|
|
29
|
+
Orbit is a *bounded, self-converging engineering execution track*:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
PLAN → EXECUTE → EVALUATE → CORRECT / RECOVER → SUCCESS
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
It is not a timer loop, an infinite auto-continue, a pure reviewer, a pure
|
|
36
|
+
planner, or an agent swarm. It is a deterministic supervisor plus Commander,
|
|
37
|
+
Executor, Smart Watchdog, durable state and bounded recovery.
|
|
38
|
+
|
|
39
|
+
## Requirements
|
|
40
|
+
|
|
41
|
+
| Component | Tested with |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `@deepseek-ai/dsh` | `0.1.5-rc.2` |
|
|
44
|
+
| `@deepseek-ai/cordis` | `4.0.2` |
|
|
45
|
+
| Node.js | `>= 22.19.0` |
|
|
46
|
+
|
|
47
|
+
Requires the DSH base services: `agents`, `subagents`, `tools`, `sessions`
|
|
48
|
+
(the standard/web profile provides them).
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
The package is published to the npm Registry; the dedicated Git distribution
|
|
53
|
+
mirror remains available when a Git source is preferred:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
dsh plugin --profile web add @kasenri/dsh-orbit
|
|
57
|
+
# Git source alternative, tracks the mirror repository HEAD:
|
|
58
|
+
# dsh plugin --profile web add github:KasenRi/dsh-orbit
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The package declares a `dsh.bundle` patch, so `dsh plugin add` registers it as a
|
|
62
|
+
profile layer automatically.
|
|
63
|
+
|
|
64
|
+
The canonical source is maintained in the
|
|
65
|
+
[source monorepo](https://github.com/KasenRi/dsh-orbit-browser-plugins/tree/main/packages/orbit).
|
|
66
|
+
The source monorepo's versioned Release tarballs remain available for manual or
|
|
67
|
+
offline fallback, but the Market uses this dedicated Git repository so updates
|
|
68
|
+
can compare the locked commit with `HEAD`.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
The `orbit_controller` tool drives the run:
|
|
73
|
+
|
|
74
|
+
| Action | Meaning |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `run` / `start` | Start a run for a goal (or continue the current one). |
|
|
77
|
+
| `resume` | Continue the persisted run after an interruption. |
|
|
78
|
+
| `status` | Inspect phase, plan, loop budget and last error. |
|
|
79
|
+
| `stop` | Close the run. |
|
|
80
|
+
| `doctor` | Read-only environment and configuration checks. |
|
|
81
|
+
|
|
82
|
+
```jsonc
|
|
83
|
+
// orbit_controller
|
|
84
|
+
{
|
|
85
|
+
"action": "run",
|
|
86
|
+
"goal": "…",
|
|
87
|
+
"approved_loop_count": 4,
|
|
88
|
+
"user_hard_constraints": ["only touch src/"]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Activation
|
|
93
|
+
|
|
94
|
+
Orbit supports three activation styles:
|
|
95
|
+
|
|
96
|
+
1. `/agent-orbit <goal>` — deterministic slash-command activation. In the Web
|
|
97
|
+
GUI it appears in the `/` menu (`Run a goal with Orbit deterministic
|
|
98
|
+
engineering orchestration`); on headless/CLI surfaces a genuine user message
|
|
99
|
+
that starts with `/agent-orbit` activates Orbit directly. The original
|
|
100
|
+
command line stays visible in the conversation, the goal is passed through
|
|
101
|
+
without rewriting, and no goal asks for one instead of starting an empty run.
|
|
102
|
+
2. `orbit模式` — recommended natural-language activation, e.g.
|
|
103
|
+
“用 orbit模式完成这个项目”.
|
|
104
|
+
3. `cx模式` — legacy compatibility; still resolves to Orbit.
|
|
105
|
+
|
|
106
|
+
All three routes converge on the existing `orbit_controller` tool and
|
|
107
|
+
`OrbitService`; the activation layer never starts a run of its own.
|
|
108
|
+
|
|
109
|
+
## Model configuration (Web)
|
|
110
|
+
|
|
111
|
+
The Orbit model control sits immediately left of the native composer model
|
|
112
|
+
seat (`conversation.input.right` renders before `conversation.input.model`).
|
|
113
|
+
Its button names the Commander's model; the menu edits three roles:
|
|
114
|
+
|
|
115
|
+
- **Commander** and **Watchdog** pick from the same native model catalog and
|
|
116
|
+
persist into the DSH `orbit` settings namespace (`settings.yaml`), with the
|
|
117
|
+
composition `config.routes` as the base/default. Switching a model uses that
|
|
118
|
+
model's own default reasoning effort — a previous model's effort is never
|
|
119
|
+
inherited.
|
|
120
|
+
- **Executor** follows the current session model ("Follows current session
|
|
121
|
+
model"). Both the Orbit row and the native seat read and write the SAME
|
|
122
|
+
per-session `ModelDirectory`, so a change in either place updates the other.
|
|
123
|
+
|
|
124
|
+
A new run resolves its routes exactly once — Commander/Watchdog from `orbit`
|
|
125
|
+
settings, Executor from the initiating session's current selection, each
|
|
126
|
+
falling back to `config.routes` — and freezes them into `state.routes`.
|
|
127
|
+
Changes made while a run is active apply to the next run; resumed runs keep
|
|
128
|
+
their frozen routes. Headless/CLI profiles without a settings provider keep
|
|
129
|
+
running from `config.routes` unchanged.
|
|
130
|
+
|
|
131
|
+
## State machine
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
PLAN → EXECUTE → EVALUATE → SUCCESS
|
|
135
|
+
│
|
|
136
|
+
├─ correction (bounded per step)
|
|
137
|
+
├─ append (bounded by remaining loop budget)
|
|
138
|
+
├─ NEEDS_USER
|
|
139
|
+
└─ BUDGET_EXHAUSTED
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- Only a normally completed Executor step consumes one loop from the budget.
|
|
143
|
+
- Corrections are limited per base step and reserve budget for the remaining
|
|
144
|
+
planned steps.
|
|
145
|
+
- Commander decisions are validated in code (`PASS_CURRENT_STEP` /
|
|
146
|
+
`CORRECT_CURRENT_STEP` / `NEEDS_USER` for step evaluation, `SUCCESS` /
|
|
147
|
+
`APPEND` / `NEEDS_USER` for final evaluation, `KEEP_APPROACH` /
|
|
148
|
+
`REPLACE_CURRENT_STEP` / `NEEDS_USER` for strategy reconsider).
|
|
149
|
+
- Commander runs under an adaptive timeout: a soft review at 360s, a second
|
|
150
|
+
review at 600s and a deterministic hard ceiling at 840s; an extension always
|
|
151
|
+
keeps the same child.
|
|
152
|
+
- The Smart Watchdog is only invoked on runtime anomalies, performs at most two
|
|
153
|
+
diagnoses per step, and can resume the same child or restart the step with a
|
|
154
|
+
fresh one after interrupting the old child.
|
|
155
|
+
- Blocked tools are recoverable: a guard denial stops that single call, not the
|
|
156
|
+
turn or the run.
|
|
157
|
+
|
|
158
|
+
## Safety boundaries
|
|
159
|
+
|
|
160
|
+
- Commander and Watchdog receive read-only tool allowlists.
|
|
161
|
+
- Executors receive the configured writer allowlist; browser tools are added
|
|
162
|
+
only for steps that declare the `browser` capability.
|
|
163
|
+
- While Orbit owns a workspace, other top-level autonomous drivers
|
|
164
|
+
(`create_goal`, `ralph`, `workflow`) are refused, and Orbit refuses to start
|
|
165
|
+
while an active goal driver owns the same workspace.
|
|
166
|
+
- `.cx` durable state is written only by the Orbit service (atomic write, short
|
|
167
|
+
lock transaction, monotonic revision).
|
|
168
|
+
|
|
169
|
+
## Configuration
|
|
170
|
+
|
|
171
|
+
| Key | Default | Meaning |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `projectDir` | session cwd | Project the run operates on. |
|
|
174
|
+
| `routes.commander` | `deepseek-official` / `deepseek-v4-pro` / `high` | Commander model route. |
|
|
175
|
+
| `routes.executor` | `deepseek-official` / `deepseek-v4-flash` / `high` | Executor model route. |
|
|
176
|
+
| `routes.watchdog` | `deepseek-official` / `deepseek-v4-flash` / `low` | Watchdog model route. |
|
|
177
|
+
| `executorTools` | read/glob/grep/bash/edit/write/… | Executor allowlist. |
|
|
178
|
+
| `browserTools` | `["agent_browser"]` | Browser capability tool names. |
|
|
179
|
+
| `commanderReadOnlyTools` | read/glob/grep/web… | Commander allowlist. |
|
|
180
|
+
| `watchdogTools` | read/glob/grep | Watchdog allowlist. |
|
|
181
|
+
| `executorTimeoutMs` | `480000` | Deterministic executor runtime timeout. |
|
|
182
|
+
| `registerTool` | `true` | Register the `orbit_controller` tool and the legacy `cx_controller` alias. |
|
|
183
|
+
| `registerGuards` | `true` | Register recoverable tool guards. |
|
|
184
|
+
| `slashCommand` | `true` | Register the `/agent-orbit` host command and the gesture boundary. |
|
|
185
|
+
|
|
186
|
+
Routes are normal DSH model routes; configure them for your own provider and
|
|
187
|
+
model identifiers. No credentials are included in this package.
|
|
188
|
+
|
|
189
|
+
## Optional browser capability
|
|
190
|
+
|
|
191
|
+
Orbit does not depend on `@kasenri/dsh-browser`. A plan step that declares
|
|
192
|
+
`capabilities: ["browser"]` needs the `agent_browser` tool to be registered by
|
|
193
|
+
the browser plugin; otherwise Orbit reports `BROWSER_CAPABILITY_UNAVAILABLE` and
|
|
194
|
+
lets the Commander decide what to do. Install both packages to use that path:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
dsh plugin --profile web add github:KasenRi/dsh-browser
|
|
198
|
+
dsh plugin --profile web add github:KasenRi/dsh-orbit
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Migrating from dsh-cx
|
|
202
|
+
|
|
203
|
+
| CX | Orbit |
|
|
204
|
+
|---|---|
|
|
205
|
+
| `dsh-cx` | `dsh-orbit` |
|
|
206
|
+
| `@kasenri/dsh-cx` | `@kasenri/dsh-orbit` |
|
|
207
|
+
| `cx_controller` | `orbit_controller` |
|
|
208
|
+
| CX mode | Orbit mode (`orbit模式`; `cx模式` still works) |
|
|
209
|
+
| `ctx.cx` | `ctx.orbit` (same `OrbitService` instance; `ctx.cx` remains an alias) |
|
|
210
|
+
|
|
211
|
+
- `.cx/state.json` remains unchanged.
|
|
212
|
+
- Legacy `cx模式` remains supported.
|
|
213
|
+
- Existing durable runs do not need migration: Orbit reads the same
|
|
214
|
+
`.cx/state.json`, including historical `CX_*` error strings.
|
|
215
|
+
- `.cx` is retained as the durable execution state path for backward
|
|
216
|
+
compatibility with existing CX projects.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @kasenri/dsh-orbit bundle layer.
|
|
2
|
+
#
|
|
3
|
+
# Adds the Orbit engineering orchestration plugin (OrbitService + orbit_controller
|
|
4
|
+
# tool; `cx_controller` remains a legacy alias) on top of the active bundle stack.
|
|
5
|
+
# Model routes use the plugin defaults and can be overridden in the profile's own
|
|
6
|
+
# cordis.patch.yml.
|
|
7
|
+
- insert:
|
|
8
|
+
- id: dsh-orbit
|
|
9
|
+
name: '@kasenri/dsh-orbit'
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic `/agent-orbit` activation.
|
|
3
|
+
*
|
|
4
|
+
* Two routes converge on the same tiny pre-step directive:
|
|
5
|
+
* - a closed-namespace DSH host command for surfaces with command adjudication
|
|
6
|
+
* (the Web GUI slash menu), and
|
|
7
|
+
* - a strict genuine-user-message gesture boundary for headless/CLI surfaces
|
|
8
|
+
* without one.
|
|
9
|
+
*
|
|
10
|
+
* Neither route creates an execution entry of its own: the directive only
|
|
11
|
+
* states that activation is explicit, and the existing `orbit_controller`
|
|
12
|
+
* tool + `OrbitService` + Supervisor remain the sole Orbit runtime.
|
|
13
|
+
*/
|
|
14
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
15
|
+
export const AGENT_ORBIT_COMMAND = 'agent-orbit';
|
|
16
|
+
/** Strict gesture: the command must begin a genuine user message line. */
|
|
17
|
+
const GESTURE = /^\/agent-orbit(?=$|[\t\n\r ])/u;
|
|
18
|
+
/** Parse one text block as a `/agent-orbit` activation. */
|
|
19
|
+
export function parseOrbitActivation(text) {
|
|
20
|
+
const trimmed = text.trimStart();
|
|
21
|
+
if (!GESTURE.test(trimmed))
|
|
22
|
+
return undefined;
|
|
23
|
+
return { goal: trimmed.slice(AGENT_ORBIT_COMMAND.length + 1).trim() };
|
|
24
|
+
}
|
|
25
|
+
/** Find the newest genuine user message that invokes `/agent-orbit`. */
|
|
26
|
+
export function invokedOrbitActivation(messages) {
|
|
27
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
28
|
+
const message = messages[index];
|
|
29
|
+
if (message === undefined || message.source.kind !== 'user')
|
|
30
|
+
continue;
|
|
31
|
+
for (const block of message.content) {
|
|
32
|
+
if (block.type !== 'text')
|
|
33
|
+
continue;
|
|
34
|
+
const activation = parseOrbitActivation(block.text);
|
|
35
|
+
if (activation !== undefined)
|
|
36
|
+
return activation;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The one deterministic directive injected for an explicit activation. It only
|
|
43
|
+
* states the activation and carries the goal verbatim; every Orbit rule still
|
|
44
|
+
* comes from the existing tool, service and protocol.
|
|
45
|
+
*/
|
|
46
|
+
export function buildOrbitActivationDirective(goal) {
|
|
47
|
+
const lines = [
|
|
48
|
+
'Orbit activation is explicit for this turn. Start or resume Orbit through the existing orbit_controller tool; do not ask the user to confirm the mode.',
|
|
49
|
+
'Treat the text following /agent-orbit as the requested goal, without summarizing or rewriting it.',
|
|
50
|
+
];
|
|
51
|
+
lines.push(goal === ''
|
|
52
|
+
? 'No goal was provided — ask the user what Orbit should accomplish; do not start an empty run.'
|
|
53
|
+
: `Goal: ${goal}`);
|
|
54
|
+
return lines.join('\n');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Register the closed-namespace `/agent-orbit` host command.
|
|
58
|
+
*
|
|
59
|
+
* The handler never injects a directive itself. It reposts the original
|
|
60
|
+
* command line as a genuine user message, so the gesture boundary stays the
|
|
61
|
+
* only activation point and a command-registered surface cannot double
|
|
62
|
+
* activate through both routes.
|
|
63
|
+
*/
|
|
64
|
+
export function registerOrbitCommand(ctx) {
|
|
65
|
+
ctx.effect(() => ctx.commands.register({
|
|
66
|
+
name: AGENT_ORBIT_COMMAND,
|
|
67
|
+
description: 'Run a goal with Orbit deterministic engineering orchestration',
|
|
68
|
+
input: { hint: 'Describe the engineering goal for Orbit' },
|
|
69
|
+
handler(invocation) {
|
|
70
|
+
const goal = invocation.rawInput.trim();
|
|
71
|
+
if (goal === '') {
|
|
72
|
+
return { kind: 'error', text: `Usage: /${AGENT_ORBIT_COMMAND} <goal> — 请输入要交给 Orbit 完成的任务。` };
|
|
73
|
+
}
|
|
74
|
+
invocation.agent.followup(createUserMessage({
|
|
75
|
+
content: [{ type: 'text', text: `/${AGENT_ORBIT_COMMAND}${invocation.rawInput}` }],
|
|
76
|
+
source: { kind: 'user' },
|
|
77
|
+
}));
|
|
78
|
+
return { kind: 'success', text: 'Orbit activated — the existing supervisor will handle this goal.' };
|
|
79
|
+
},
|
|
80
|
+
}), 'dsh-orbit: /agent-orbit host command');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Install the gesture boundary. It runs for every proposed step and injects
|
|
84
|
+
* the activation directive once, for the step that carries the genuine user
|
|
85
|
+
* message. The in-step guard keeps a step that already holds an Orbit
|
|
86
|
+
* directive from gaining a second one, without any durable state.
|
|
87
|
+
*/
|
|
88
|
+
export function installOrbitGestureBoundary(ctx) {
|
|
89
|
+
ctx.on('agent/pre-step', async ({ messages, signal }, next) => {
|
|
90
|
+
const decision = await next();
|
|
91
|
+
if (decision.kind === 'reject')
|
|
92
|
+
return decision;
|
|
93
|
+
if (decision.messages.some((message) => message.source.kind === 'orbit-command'))
|
|
94
|
+
return decision;
|
|
95
|
+
const activation = invokedOrbitActivation(messages);
|
|
96
|
+
if (activation === undefined)
|
|
97
|
+
return decision;
|
|
98
|
+
signal.throwIfAborted();
|
|
99
|
+
return {
|
|
100
|
+
kind: 'enter',
|
|
101
|
+
messages: [
|
|
102
|
+
...decision.messages,
|
|
103
|
+
createUserMessage({
|
|
104
|
+
content: [{ type: 'text', text: buildOrbitActivationDirective(activation.goal) }],
|
|
105
|
+
source: { kind: 'orbit-command', ...(activation.goal === '' ? {} : { goal: activation.goal }) },
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
}
|