@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 CHANGED
@@ -1,15 +1,13 @@
1
1
  /**
2
- * Deterministic `/agent-orbit` activation.
2
+ * Deterministic Orbit activation.
3
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.
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 and injects
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. Only when no explicit activation is present does the
145
- * Session toggle (when the composition provides it) promote an ordinary user
146
- * message into an Orbit goal.
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
- const implicit = explicit === undefined && options.sessionEnabled?.(agent.session) === true
157
- ? invokedOrbitMessage(messages)
158
- : undefined;
159
- if (explicit === undefined && implicit === undefined)
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
- const activation = explicit ?? implicit ?? { goal: '' };
163
- const directive = explicit === undefined
164
- ? buildOrbitSessionDirective(activation.goal)
165
- : buildOrbitActivationDirective(activation.goal);
166
- return {
167
- kind: 'enter',
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);letter-spacing:.04em;text-transform:uppercase;padding:6px 8px 2px;font-size:11px}.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}";
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
- "error": "f77nca_error",
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
- "check": "f77nca_check",
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("orbit")
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: t("models")
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("nextRunOnly")
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
- orbit: "Orbit",
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
- nextRunOnly: "Changes apply to the next Orbit run"
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
- orbit: "Orbit",
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
- nextRunOnly: "更改应用于下一个新的 Orbit 运行"
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",
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",