@kasenri/dsh-orbit 0.5.3 → 0.5.5
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/lib/activation.js +37 -46
- package/lib/client.js +29 -26
- package/lib/index.js +23 -0
- package/package.json +1 -1
package/lib/activation.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Deterministic
|
|
2
|
+
* Deterministic Orbit activation.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* states that activation is explicit, and the existing `orbit_controller`
|
|
12
|
-
* tool + `OrbitService` + Supervisor remain the sole Orbit runtime.
|
|
4
|
+
* - `/agent-orbit` (host command or genuine-message gesture) keeps its explicit
|
|
5
|
+
* directive; the existing `orbit_controller` tool + `OrbitService` remain the
|
|
6
|
+
* runtime.
|
|
7
|
+
* - A Session whose toggle is ON hands every ordinary user message straight to
|
|
8
|
+
* `OrbitService`: the pre-step boundary consumes the turn (no parent model
|
|
9
|
+
* call, no parent mutation) and the host starts or resumes the run. The model
|
|
10
|
+
* never decides whether Orbit runs.
|
|
13
11
|
*/
|
|
14
12
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
15
13
|
import { ORBIT_TOGGLE_COMMAND, parseOrbitToggle } from "./session-state.js";
|
|
@@ -70,17 +68,6 @@ export function buildOrbitActivationDirective(goal) {
|
|
|
70
68
|
: `Goal: ${goal}`);
|
|
71
69
|
return lines.join('\n');
|
|
72
70
|
}
|
|
73
|
-
/**
|
|
74
|
-
* The directive for a Session whose toggle is ON: an ordinary user message
|
|
75
|
-
* becomes the Orbit goal without changing the activation machinery.
|
|
76
|
-
*/
|
|
77
|
-
export function buildOrbitSessionDirective(goal) {
|
|
78
|
-
return [
|
|
79
|
-
'Orbit is enabled for this chat, so treat this ordinary user message as the requested goal. Start or resume Orbit through the existing orbit_controller tool; do not ask the user to confirm the mode.',
|
|
80
|
-
'Use the message as the goal, without summarizing or rewriting it.',
|
|
81
|
-
`Goal: ${goal}`,
|
|
82
|
-
].join('\n');
|
|
83
|
-
}
|
|
84
71
|
/**
|
|
85
72
|
* Register the closed-namespace `/agent-orbit` host command.
|
|
86
73
|
*
|
|
@@ -135,15 +122,13 @@ export function registerOrbitToggleCommand(ctx) {
|
|
|
135
122
|
}), 'dsh-orbit: /orbit-toggle host command');
|
|
136
123
|
}
|
|
137
124
|
/**
|
|
138
|
-
* Install the gesture boundary. It runs for every proposed step
|
|
139
|
-
* the activation directive once, for the step that carries the genuine user
|
|
140
|
-
* message. The in-step guard keeps a step that already holds an Orbit
|
|
141
|
-
* directive from gaining a second one, without any durable state.
|
|
125
|
+
* Install the gesture boundary. It runs for every proposed step.
|
|
142
126
|
*
|
|
143
127
|
* An explicit `/agent-orbit` always wins and always activates, whatever the
|
|
144
|
-
* Session toggle says
|
|
145
|
-
*
|
|
146
|
-
* message
|
|
128
|
+
* Session toggle says: it keeps the existing activation directive and the
|
|
129
|
+
* `orbit_controller` tool. Otherwise, an enabled Session hands the ordinary
|
|
130
|
+
* user message to Orbit directly — the step is consumed with no model call and
|
|
131
|
+
* the message stays in the conversation as durable history.
|
|
147
132
|
*/
|
|
148
133
|
export function installOrbitGestureBoundary(ctx, options = {}) {
|
|
149
134
|
ctx.on('agent/pre-step', async ({ agent, messages, signal }, next) => {
|
|
@@ -153,25 +138,31 @@ export function installOrbitGestureBoundary(ctx, options = {}) {
|
|
|
153
138
|
if (decision.messages.some((message) => message.source.kind === 'orbit-command'))
|
|
154
139
|
return decision;
|
|
155
140
|
const explicit = invokedOrbitActivation(messages);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
141
|
+
if (explicit !== undefined) {
|
|
142
|
+
signal.throwIfAborted();
|
|
143
|
+
return {
|
|
144
|
+
kind: 'enter',
|
|
145
|
+
messages: [
|
|
146
|
+
...decision.messages,
|
|
147
|
+
createUserMessage({
|
|
148
|
+
content: [{ type: 'text', text: buildOrbitActivationDirective(explicit.goal) }],
|
|
149
|
+
source: { kind: 'orbit-command', ...(explicit.goal === '' ? {} : { goal: explicit.goal }) },
|
|
150
|
+
}),
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (options.sessionEnabled?.(agent.session) !== true)
|
|
155
|
+
return decision;
|
|
156
|
+
const ordinary = invokedOrbitMessage(messages);
|
|
157
|
+
const activate = options.activate;
|
|
158
|
+
if (ordinary === undefined || activate === undefined)
|
|
160
159
|
return decision;
|
|
161
160
|
signal.throwIfAborted();
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
messages: [
|
|
169
|
-
...decision.messages,
|
|
170
|
-
createUserMessage({
|
|
171
|
-
content: [{ type: 'text', text: directive }],
|
|
172
|
-
source: { kind: 'orbit-command', ...(activation.goal === '' ? {} : { goal: activation.goal }) },
|
|
173
|
-
}),
|
|
174
|
-
],
|
|
175
|
-
};
|
|
161
|
+
// The claimed batch enters the conversation exactly once: the loop commits
|
|
162
|
+
// `decision.messages`, which this path leaves empty.
|
|
163
|
+
for (const message of messages)
|
|
164
|
+
agent.session.append('user/message', message, { surfaceOp: 'append' });
|
|
165
|
+
await activate(agent, ordinary.goal, signal);
|
|
166
|
+
return { kind: 'enter', messages: [] };
|
|
176
167
|
});
|
|
177
168
|
}
|
package/lib/client.js
CHANGED
|
@@ -122,7 +122,7 @@ window.__ModuleLoader__.load({
|
|
|
122
122
|
}
|
|
123
123
|
//#endregion
|
|
124
124
|
//#region \0dsh-css:/root/code/dsh-pi-parity/packages/orbit/client/OrbitModelSelect.module.css.mjs
|
|
125
|
-
const css = ".f77nca_panel{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu);min-width:260px;max-width:420px;max-height:min(55vh,420px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:6px;font-size:13px;line-height:1.4;display:flex;position:fixed;overflow:auto}.f77nca_title{color:var(--dsw-alias-label-tertiary);
|
|
125
|
+
const css = ".f77nca_panel{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu);min-width:260px;max-width:420px;max-height:min(55vh,420px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:6px;font-size:13px;line-height:1.4;display:flex;position:fixed;overflow:auto}.f77nca_title{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;padding:6px 8px 2px;font-size:11px;overflow:hidden}.f77nca_group{color:var(--dsw-alias-label-tertiary);padding:8px 8px 2px;font-size:11px}.f77nca_row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;align-items:center;gap:8px;padding:7px 8px;display:flex}.f77nca_row:hover{background:var(--dsw-alias-interactive-bg-hover)}.f77nca_switchRow{align-items:center;gap:8px;padding:4px 8px 6px;display:flex}.f77nca_switchControl{margin-left:auto}.f77nca_rowLabel{flex:none}.f77nca_rowValue{max-width:190px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;margin-left:auto;overflow:hidden}.f77nca_rowValueActive{color:var(--dsw-alias-label-primary)}.f77nca_rowDetail{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}.f77nca_check{color:var(--dsw-alias-state-business-primary);flex:none;margin-left:6px}.f77nca_chevron{color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px}.f77nca_separator{background:var(--dsw-alias-border-l1);height:1px;margin:6px 4px}.f77nca_hint{color:var(--dsw-alias-label-tertiary);padding:6px 8px;font-size:11px}.f77nca_error{color:var(--dsw-alias-state-error-primary);align-items:center;gap:8px;padding:8px;font-size:12px;display:flex}.f77nca_back{width:100%;color:var(--dsw-alias-label-tertiary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:6px 8px 8px;font-size:12px;display:flex}";
|
|
126
126
|
const tagId = "@kasenri/dsh-orbit/OrbitModelSelect.module.css";
|
|
127
127
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
128
128
|
const tag = document.createElement("style");
|
|
@@ -132,22 +132,22 @@ window.__ModuleLoader__.load({
|
|
|
132
132
|
document.head.appendChild(tag);
|
|
133
133
|
}
|
|
134
134
|
var OrbitModelSelect_module_css_default = {
|
|
135
|
-
"
|
|
136
|
-
"chevron": "f77nca_chevron",
|
|
137
|
-
"back": "f77nca_back",
|
|
138
|
-
"rowValueActive": "f77nca_rowValueActive",
|
|
139
|
-
"hint": "f77nca_hint",
|
|
135
|
+
"check": "f77nca_check",
|
|
140
136
|
"switchControl": "f77nca_switchControl",
|
|
141
|
-
"group": "f77nca_group",
|
|
142
|
-
"panel": "f77nca_panel",
|
|
143
|
-
"separator": "f77nca_separator",
|
|
144
|
-
"title": "f77nca_title",
|
|
145
137
|
"switchRow": "f77nca_switchRow",
|
|
146
|
-
"rowValue": "f77nca_rowValue",
|
|
147
138
|
"rowDetail": "f77nca_rowDetail",
|
|
148
|
-
"
|
|
139
|
+
"title": "f77nca_title",
|
|
140
|
+
"panel": "f77nca_panel",
|
|
149
141
|
"row": "f77nca_row",
|
|
150
|
-
"rowLabel": "f77nca_rowLabel"
|
|
142
|
+
"rowLabel": "f77nca_rowLabel",
|
|
143
|
+
"group": "f77nca_group",
|
|
144
|
+
"error": "f77nca_error",
|
|
145
|
+
"rowValueActive": "f77nca_rowValueActive",
|
|
146
|
+
"separator": "f77nca_separator",
|
|
147
|
+
"chevron": "f77nca_chevron",
|
|
148
|
+
"rowValue": "f77nca_rowValue",
|
|
149
|
+
"back": "f77nca_back",
|
|
150
|
+
"hint": "f77nca_hint"
|
|
151
151
|
};
|
|
152
152
|
//#endregion
|
|
153
153
|
//#region client/OrbitModelSelect.tsx
|
|
@@ -249,6 +249,7 @@ window.__ModuleLoader__.load({
|
|
|
249
249
|
};
|
|
250
250
|
const currentRouteOf = (role) => role === "commander" ? config.commander : role === "watchdog" ? config.watchdog : executorRoute;
|
|
251
251
|
const roleLabelOf = (role) => role === "commander" ? commanderLabel : role === "watchdog" ? watchdogLabel : executorLabel;
|
|
252
|
+
const roleModelLabelOf = (role) => t(role === "commander" ? "commanderModel" : role === "executor" ? "executorModel" : "watchdogModel");
|
|
252
253
|
const roleEffortLabelOf = (role) => role === "commander" ? commanderEffort : role === "watchdog" ? watchdogEffort : executorEffort;
|
|
253
254
|
const commitEffort = async (role, route, effort) => {
|
|
254
255
|
const next = {
|
|
@@ -371,7 +372,7 @@ window.__ModuleLoader__.load({
|
|
|
371
372
|
className: OrbitModelSelect_module_css_default.switchRow,
|
|
372
373
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
373
374
|
className: OrbitModelSelect_module_css_default.rowLabel,
|
|
374
|
-
children: t("
|
|
375
|
+
children: t("enableLongRun")
|
|
375
376
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
376
377
|
className: OrbitModelSelect_module_css_default.switchControl,
|
|
377
378
|
checked: orbitEnabled,
|
|
@@ -467,10 +468,6 @@ window.__ModuleLoader__.load({
|
|
|
467
468
|
})
|
|
468
469
|
] }) : null,
|
|
469
470
|
pane.kind === "role" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
470
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
471
|
-
className: OrbitModelSelect_module_css_default.group,
|
|
472
|
-
children: t(pane.role)
|
|
473
|
-
}),
|
|
474
471
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
475
472
|
type: "button",
|
|
476
473
|
role: "menuitem",
|
|
@@ -485,7 +482,7 @@ window.__ModuleLoader__.load({
|
|
|
485
482
|
children: [
|
|
486
483
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
487
484
|
className: OrbitModelSelect_module_css_default.rowLabel,
|
|
488
|
-
children:
|
|
485
|
+
children: roleModelLabelOf(pane.role)
|
|
489
486
|
}),
|
|
490
487
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
491
488
|
className: OrbitModelSelect_module_css_default.rowValue,
|
|
@@ -564,7 +561,7 @@ window.__ModuleLoader__.load({
|
|
|
564
561
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }),
|
|
565
562
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
566
563
|
className: OrbitModelSelect_module_css_default.hint,
|
|
567
|
-
children: t("
|
|
564
|
+
children: t("applyOnNextSend")
|
|
568
565
|
})
|
|
569
566
|
]
|
|
570
567
|
}), document.body) : null] });
|
|
@@ -576,13 +573,16 @@ window.__ModuleLoader__.load({
|
|
|
576
573
|
const en = {
|
|
577
574
|
triggerFallback: "Orbit",
|
|
578
575
|
tooltip: "Orbit model configuration",
|
|
579
|
-
title: "Orbit",
|
|
580
|
-
|
|
576
|
+
title: "Orbit — Self-reviewing continuous execution",
|
|
577
|
+
enableLongRun: "Enable long-running execution",
|
|
581
578
|
orbitOff: "Orbit Off",
|
|
582
579
|
orbitSwitchLabel: "Orbit for this chat",
|
|
583
580
|
commander: "Commander",
|
|
584
581
|
executor: "Executor",
|
|
585
582
|
watchdog: "Watchdog",
|
|
583
|
+
commanderModel: "Commander model",
|
|
584
|
+
executorModel: "Executor model",
|
|
585
|
+
watchdogModel: "Watchdog model",
|
|
586
586
|
followsSession: "Follows current session model",
|
|
587
587
|
models: "Model",
|
|
588
588
|
effort: "Reasoning effort",
|
|
@@ -592,19 +592,22 @@ window.__ModuleLoader__.load({
|
|
|
592
592
|
loadFailed: "Failed to load models",
|
|
593
593
|
settingsFailed: "Failed to load Orbit settings",
|
|
594
594
|
saveFailed: "Failed to save Orbit settings",
|
|
595
|
-
|
|
595
|
+
applyOnNextSend: "Changes apply to the next message"
|
|
596
596
|
};
|
|
597
597
|
/** Chinese strings. */
|
|
598
598
|
const zh = {
|
|
599
599
|
triggerFallback: "Orbit",
|
|
600
600
|
tooltip: "Orbit 模型配置",
|
|
601
|
-
title: "Orbit",
|
|
602
|
-
|
|
601
|
+
title: "Orbit 让AI自我审核连续执行",
|
|
602
|
+
enableLongRun: "启用一键长执行",
|
|
603
603
|
orbitOff: "Orbit Off",
|
|
604
604
|
orbitSwitchLabel: "本会话 Orbit 开关",
|
|
605
605
|
commander: "指挥官",
|
|
606
606
|
executor: "执行员",
|
|
607
607
|
watchdog: "监控模型",
|
|
608
|
+
commanderModel: "指挥官模型",
|
|
609
|
+
executorModel: "执行员模型",
|
|
610
|
+
watchdogModel: "监控模型",
|
|
608
611
|
followsSession: "跟随当前会话模型",
|
|
609
612
|
models: "模型",
|
|
610
613
|
effort: "推理等级",
|
|
@@ -614,7 +617,7 @@ window.__ModuleLoader__.load({
|
|
|
614
617
|
loadFailed: "模型列表加载失败",
|
|
615
618
|
settingsFailed: "Orbit 设置加载失败",
|
|
616
619
|
saveFailed: "Orbit 设置保存失败",
|
|
617
|
-
|
|
620
|
+
applyOnNextSend: "更改将会在下一次发送时生效"
|
|
618
621
|
};
|
|
619
622
|
//#endregion
|
|
620
623
|
//#region client/index.ts
|
package/lib/index.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import z from '@deepseek-ai/schemastery';
|
|
2
2
|
import { installOrbitGestureBoundary, registerOrbitCommand, registerOrbitToggleCommand } from "./activation.js";
|
|
3
|
+
import { estimateLoopCount } from "./kernel.js";
|
|
3
4
|
import { createOrbitPreExecuteHandler } from "./pipeline-guard.js";
|
|
4
5
|
import { resolveEffectiveRoutes, sessionSelectionOf } from "./routes.js";
|
|
5
6
|
import { installOrbitSessionProjection, orbitEnabledOf } from "./session-state.js";
|
|
6
7
|
import { OrbitService } from "./service.js";
|
|
7
8
|
import { createOrbitTool } from "./tool.js";
|
|
9
|
+
/**
|
|
10
|
+
* Minimum loop budget for a hard-activated run. The Commander is asked for a
|
|
11
|
+
* 2-5 step plan and every executed step consumes one loop slot, so the host
|
|
12
|
+
* must grant a budget that can finish a full plan; the goal complexity
|
|
13
|
+
* estimate raises it further when the goal asks for more.
|
|
14
|
+
*/
|
|
15
|
+
const HARD_ACTIVATION_MIN_LOOPS = 5;
|
|
8
16
|
export const name = 'dsh-orbit';
|
|
9
17
|
export const inject = ['tools', 'agents', 'subagents'];
|
|
10
18
|
const Route = z.object({
|
|
@@ -117,6 +125,21 @@ export function apply(ctx, config) {
|
|
|
117
125
|
});
|
|
118
126
|
installOrbitGestureBoundary(ctx, {
|
|
119
127
|
sessionEnabled: (session) => orbitEnabledOf(ctx, session),
|
|
128
|
+
activate: async (agent, goal, signal) => {
|
|
129
|
+
const cwd = agent.session.header.cwd ?? process.cwd();
|
|
130
|
+
try {
|
|
131
|
+
// The initiator scope makes the run's children belong to this Agent;
|
|
132
|
+
// the parent model is never asked to decide or to run the task.
|
|
133
|
+
await ctx.agents.withInitiator(agent, () => service.run({
|
|
134
|
+
goal,
|
|
135
|
+
approved_loop_count: Math.max(estimateLoopCount(goal), HARD_ACTIVATION_MIN_LOOPS),
|
|
136
|
+
}, cwd, signal));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Durable run state owns failure reporting; a takeover failure must
|
|
140
|
+
// not fail the consumed parent turn.
|
|
141
|
+
}
|
|
142
|
+
},
|
|
120
143
|
});
|
|
121
144
|
}
|
|
122
145
|
// Per-Session Orbit enable state: natively durable through the Session log
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kasenri/dsh-orbit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deterministic engineering orchestration for DeepSeek Harness with Commander, Executor, Smart Watchdog, bounded recovery and durable execution state.",
|
|
6
6
|
"license": "MIT",
|