@kasenri/dsh-orbit 0.5.8 → 0.5.10
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/README.md +16 -5
- package/lib/activation.js +3 -2
- package/lib/client.js +22 -12
- package/lib/dsh-host.js +4 -0
- package/lib/index.js +27 -11
- package/lib/kernel.js +27 -3
- package/lib/supervisor.js +14 -5
- package/lib/types.js +3 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
Community plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH).
|
|
4
4
|
Not affiliated with or endorsed by DeepSeek.
|
|
5
5
|
|
|
6
|
+
**让 AI 项目可以在无人监管下持续推进。**
|
|
7
|
+
Orbit 会自动规划任务、分工执行、逐步检查并继续完成后续工作;不同环节可以使用不同模型,让低成本模型承担执行任务、强模型负责规划和审核,从而降低整体 AI 使用成本。Watchdog 还会监控运行异常,在任务卡死或中断时协助恢复。
|
|
8
|
+
|
|
6
9
|
**Orbit — Deterministic Engineering Orchestration for DeepSeek Harness**
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
as a Cordis plugin:
|
|
11
|
+
Technical integration:
|
|
10
12
|
|
|
11
13
|
- an `OrbitService` on `ctx.orbit`
|
|
12
14
|
- a model-facing `orbit_controller` tool (`cx_controller` remains a legacy alias)
|
|
@@ -104,12 +106,16 @@ Orbit supports three activation styles:
|
|
|
104
106
|
|
|
105
107
|
All three routes converge on the existing `orbit_controller` tool and
|
|
106
108
|
`OrbitService`; the activation layer never starts a run of its own.
|
|
109
|
+
After a hard-activated run reaches `SUCCESS`, the initiating Session displays
|
|
110
|
+
the Final Commander's user-visible result directly, with the Commander's frozen
|
|
111
|
+
provider/model provenance. The parent model and parent tools remain bypassed.
|
|
107
112
|
|
|
108
113
|
## Model configuration (Web)
|
|
109
114
|
|
|
110
|
-
The Orbit model control
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
The Orbit model control is the final entry in `conversation.input.right`, so
|
|
116
|
+
other composer-side controls (for example DSH's rollback control) stay to its
|
|
117
|
+
left while the native `conversation.input.model` seat stays immediately to its
|
|
118
|
+
right. Its button names the Commander's model; the menu edits three roles:
|
|
113
119
|
|
|
114
120
|
- **Commander** and **Watchdog** pick from the same native model catalog and
|
|
115
121
|
persist into the DSH `orbit` settings namespace (`settings.yaml`). Picking a
|
|
@@ -140,6 +146,11 @@ PLAN → EXECUTE → EVALUATE → SUCCESS
|
|
|
140
146
|
```
|
|
141
147
|
|
|
142
148
|
- Only a normally completed Executor step consumes one loop from the budget.
|
|
149
|
+
- Runs without an explicit user/tool budget start from the historical floor of
|
|
150
|
+
5 loops; after PLAN, Orbit deterministically reserves two extra bounded slots
|
|
151
|
+
beyond the accepted base plan (`max(5, steps + 2)`, therefore at most 7 for
|
|
152
|
+
the 1–5-step plan schema). Explicit `approved_loop_count` / `max_loops`
|
|
153
|
+
values are never enlarged automatically.
|
|
143
154
|
- Corrections are limited per base step and reserve budget for the remaining
|
|
144
155
|
planned steps.
|
|
145
156
|
- Commander decisions are validated in code (`PASS_CURRENT_STEP` /
|
package/lib/activation.js
CHANGED
|
@@ -116,7 +116,8 @@ export function registerOrbitToggleCommand(ctx) {
|
|
|
116
116
|
* call while the message stays in the conversation as durable history.
|
|
117
117
|
*/
|
|
118
118
|
export function installOrbitGestureBoundary(ctx, options = {}) {
|
|
119
|
-
ctx.on('agent/pre-step', async (
|
|
119
|
+
ctx.on('agent/pre-step', async (payload, next) => {
|
|
120
|
+
const { agent, messages, signal } = payload;
|
|
120
121
|
const decision = await next();
|
|
121
122
|
if (decision.kind === 'reject')
|
|
122
123
|
return decision;
|
|
@@ -134,7 +135,7 @@ export function installOrbitGestureBoundary(ctx, options = {}) {
|
|
|
134
135
|
// `decision.messages`, which this path leaves empty.
|
|
135
136
|
for (const message of messages)
|
|
136
137
|
agent.session.append('user/message', message, { surfaceOp: 'append' });
|
|
137
|
-
await activate(agent, goal, signal);
|
|
138
|
+
await activate(agent, goal, { turn: payload.turn, step: payload.step }, signal);
|
|
138
139
|
return { kind: 'enter', messages: [] };
|
|
139
140
|
});
|
|
140
141
|
}
|
package/lib/client.js
CHANGED
|
@@ -94,22 +94,22 @@ window.__ModuleLoader__.load({
|
|
|
94
94
|
document.head.appendChild(tag);
|
|
95
95
|
}
|
|
96
96
|
var OrbitModelSelect_module_css_default = {
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"rowValue": "f77nca_rowValue",
|
|
100
|
-
"switchControl": "f77nca_switchControl",
|
|
97
|
+
"check": "f77nca_check",
|
|
98
|
+
"chevron": "f77nca_chevron",
|
|
101
99
|
"rowDetail": "f77nca_rowDetail",
|
|
102
|
-
"
|
|
103
|
-
"switchRow": "f77nca_switchRow",
|
|
100
|
+
"title": "f77nca_title",
|
|
104
101
|
"separator": "f77nca_separator",
|
|
105
|
-
"chevron": "f77nca_chevron",
|
|
106
102
|
"row": "f77nca_row",
|
|
107
103
|
"group": "f77nca_group",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
104
|
+
"panel": "f77nca_panel",
|
|
105
|
+
"rowLabel": "f77nca_rowLabel",
|
|
106
|
+
"rowValue": "f77nca_rowValue",
|
|
107
|
+
"hint": "f77nca_hint",
|
|
111
108
|
"back": "f77nca_back",
|
|
112
|
-
"
|
|
109
|
+
"switchControl": "f77nca_switchControl",
|
|
110
|
+
"switchRow": "f77nca_switchRow",
|
|
111
|
+
"error": "f77nca_error",
|
|
112
|
+
"rowValueActive": "f77nca_rowValueActive"
|
|
113
113
|
};
|
|
114
114
|
//#endregion
|
|
115
115
|
//#region client/OrbitModelSelect.tsx
|
|
@@ -592,6 +592,13 @@ window.__ModuleLoader__.load({
|
|
|
592
592
|
//#region client/index.ts
|
|
593
593
|
/** The host settings namespace Orbit registers for its own two roles. */
|
|
594
594
|
const ORBIT_SETTINGS_NS = "orbit";
|
|
595
|
+
/**
|
|
596
|
+
* Keep Orbit as the final list entry in `conversation.input.right`.
|
|
597
|
+
* DSH renders the whole right list before the named model seat, so this gives
|
|
598
|
+
* the stable local order: other right-side controls → Orbit → model selector.
|
|
599
|
+
*/
|
|
600
|
+
const ORBIT_INPUT_RIGHT_PRIORITY = Number.MAX_SAFE_INTEGER;
|
|
601
|
+
const ORBIT_INPUT_RIGHT_ORDER = Number.MAX_SAFE_INTEGER;
|
|
595
602
|
/** Required client services: slots, the shared model directory, Remote (settings namespace), and locale. */
|
|
596
603
|
const inject = [
|
|
597
604
|
"slots",
|
|
@@ -718,13 +725,16 @@ window.__ModuleLoader__.load({
|
|
|
718
725
|
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
719
726
|
name: "conversation.input.right",
|
|
720
727
|
id: "orbit-model",
|
|
721
|
-
|
|
728
|
+
priority: ORBIT_INPUT_RIGHT_PRIORITY,
|
|
729
|
+
order: ORBIT_INPUT_RIGHT_ORDER,
|
|
722
730
|
locale: NS,
|
|
723
731
|
inject: injected
|
|
724
732
|
}, OrbitModelSelect));
|
|
725
733
|
});
|
|
726
734
|
}
|
|
727
735
|
//#endregion
|
|
736
|
+
exports.ORBIT_INPUT_RIGHT_ORDER = ORBIT_INPUT_RIGHT_ORDER;
|
|
737
|
+
exports.ORBIT_INPUT_RIGHT_PRIORITY = ORBIT_INPUT_RIGHT_PRIORITY;
|
|
728
738
|
exports.ORBIT_SETTINGS_NS = ORBIT_SETTINGS_NS;
|
|
729
739
|
exports.apply = apply;
|
|
730
740
|
exports.inject = inject;
|
package/lib/dsh-host.js
CHANGED
|
@@ -13,6 +13,9 @@ function contentToText(blocks) {
|
|
|
13
13
|
.map((block) => (block.type === 'text' ? block.text : `[${block.type}]`))
|
|
14
14
|
.join('\n');
|
|
15
15
|
}
|
|
16
|
+
function visibleContentToText(blocks) {
|
|
17
|
+
return blocks?.flatMap((block) => block.type === 'text' && block.text.trim() !== '' ? [block.text] : []).join('\n') ?? '';
|
|
18
|
+
}
|
|
16
19
|
/**
|
|
17
20
|
* Wire the Orbit supervisor to DeepSeek Harness native Agent/Subagent services.
|
|
18
21
|
*
|
|
@@ -81,6 +84,7 @@ export class DshOrbitHost {
|
|
|
81
84
|
.then((value) => ({
|
|
82
85
|
childId: run.id,
|
|
83
86
|
output: contentToText(value.output),
|
|
87
|
+
visibleOutput: visibleContentToText(value.output),
|
|
84
88
|
interrupted: value.stopReason !== 'completed',
|
|
85
89
|
...(value.stopReason !== 'completed' ? { reason: value.stopReason } : {}),
|
|
86
90
|
...(value.diagnostic ? { testSummary: [value.diagnostic] } : {}),
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
1
|
+
import { AssistantStreamAccumulator, boundContextSummary, createAssistantMessage, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
2
|
import z from '@deepseek-ai/schemastery';
|
|
3
3
|
import { installOrbitGestureBoundary, registerOrbitCommand, registerOrbitToggleCommand } from "./activation.js";
|
|
4
4
|
import { createOrbitPreExecuteHandler } from "./pipeline-guard.js";
|
|
@@ -6,11 +6,6 @@ import { agentDefaultSelectionOf, resolveEffectiveRoutes, sessionModelSelectionO
|
|
|
6
6
|
import { installOrbitSessionProjection, orbitEnabledOf } from "./session-state.js";
|
|
7
7
|
import { OrbitService } from "./service.js";
|
|
8
8
|
import { createOrbitTool } from "./tool.js";
|
|
9
|
-
/**
|
|
10
|
-
* Fixed hard-activation budget. Explicit tool calls may still supply a bounded
|
|
11
|
-
* user-owned budget; ordinary activation never guesses complexity from words.
|
|
12
|
-
*/
|
|
13
|
-
const HARD_ACTIVATION_LOOP_BUDGET = 5;
|
|
14
9
|
export const name = 'dsh-orbit';
|
|
15
10
|
export const inject = ['tools', 'agents', 'subagents'];
|
|
16
11
|
const Route = z.object({
|
|
@@ -120,21 +115,22 @@ export function apply(ctx, config) {
|
|
|
120
115
|
});
|
|
121
116
|
installOrbitGestureBoundary(ctx, {
|
|
122
117
|
sessionEnabled: (session) => orbitEnabledOf(ctx, session),
|
|
123
|
-
activate: async (agent, goal, signal) => {
|
|
118
|
+
activate: async (agent, goal, position, signal) => {
|
|
124
119
|
const cwd = agent.session.header.cwd ?? process.cwd();
|
|
125
120
|
let result;
|
|
126
121
|
try {
|
|
127
122
|
// The initiator scope makes the run's children belong to this Agent;
|
|
128
123
|
// the parent model is never asked to decide or to run the task.
|
|
129
|
-
result = await ctx.agents.withInitiator(agent, () => service.run({
|
|
130
|
-
goal,
|
|
131
|
-
approved_loop_count: HARD_ACTIVATION_LOOP_BUDGET,
|
|
132
|
-
}, cwd, signal));
|
|
124
|
+
result = await ctx.agents.withInitiator(agent, () => service.run({ goal }, cwd, signal));
|
|
133
125
|
}
|
|
134
126
|
catch (error) {
|
|
135
127
|
appendOrbitNotice(agent.session, `Orbit 启动失败:${error instanceof Error ? error.message : String(error)}`);
|
|
136
128
|
return;
|
|
137
129
|
}
|
|
130
|
+
if (result.ok && result.phase === 'SUCCESS' && result.final_output !== undefined) {
|
|
131
|
+
appendOrbitFinalOutput(agent.session, position, result.final_output);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
138
134
|
const notice = activationNotice(result);
|
|
139
135
|
if (notice !== undefined)
|
|
140
136
|
appendOrbitNotice(agent.session, notice);
|
|
@@ -168,6 +164,26 @@ export function apply(ctx, config) {
|
|
|
168
164
|
ctx.on('tools/pre-execute', (exec, next) => handler(exec, next));
|
|
169
165
|
}
|
|
170
166
|
}
|
|
167
|
+
/** Append the existing Final Commander answer as this consumed turn's sole assistant result. */
|
|
168
|
+
function appendOrbitFinalOutput(session, position, output) {
|
|
169
|
+
const message = createAssistantMessage({
|
|
170
|
+
content: [{ type: 'text', text: output.text }],
|
|
171
|
+
source: { provider: output.provider, model: output.model },
|
|
172
|
+
});
|
|
173
|
+
const stream = new AssistantStreamAccumulator();
|
|
174
|
+
const time = Date.now();
|
|
175
|
+
stream.push({ time, chunk: { type: 'block-start', index: 0, blockType: 'text' } });
|
|
176
|
+
stream.push({ time, chunk: { type: 'text-delta', index: 0, text: output.text } });
|
|
177
|
+
stream.push({ time, chunk: { type: 'block-end', index: 0, block: { type: 'text', text: output.text } } });
|
|
178
|
+
stream.push({ time, chunk: { type: 'finish', reason: { kind: 'stop' } } });
|
|
179
|
+
session.append('step/start', position);
|
|
180
|
+
try {
|
|
181
|
+
session.append('assistant/message', { ...position, message, stream: [...stream.snapshot()] }, { surfaceOp: 'append' });
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
session.append('step/end', position);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
171
187
|
/**
|
|
172
188
|
* One durable, user-visible Orbit notice. The DSH `plugin` + `form: 'notice'`
|
|
173
189
|
* source renders as a collapsed notice row instead of a user message, and the
|
package/lib/kernel.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* read a clock, or use randomness. Runtime values (routes, timestamps, run ids)
|
|
6
6
|
* are supplied by the supervisor, which owns orchestration and persistence.
|
|
7
7
|
*/
|
|
8
|
-
import { MAX_CORRECTION_DEPTH, DEFAULT_LOOP_BUDGET, MAX_PLAN_STEPS, MAX_WATCHDOG_CALLS_PER_STEP, MIN_PLAN_STEPS, ORBIT_SCHEMA_VERSION, } from "./types.js";
|
|
8
|
+
import { MAX_CORRECTION_DEPTH, DEFAULT_LOOP_BUDGET, AUTOMATIC_LOOP_RECOVERY_RESERVE, MAX_AUTOMATIC_LOOP_BUDGET, MAX_PLAN_STEPS, MAX_WATCHDOG_CALLS_PER_STEP, MIN_PLAN_STEPS, ORBIT_SCHEMA_VERSION, } from "./types.js";
|
|
9
9
|
/** Capabilities a plan step may request. */
|
|
10
10
|
export const ORBIT_CAPABILITIES = ['filesystem', 'shell', 'web', 'browser'];
|
|
11
11
|
const STEP_CAPABILITIES = new Set(ORBIT_CAPABILITIES);
|
|
@@ -83,6 +83,29 @@ export function updateLoopBudget(state, budget) {
|
|
|
83
83
|
state.loop_count = state.loop.used;
|
|
84
84
|
state.remaining_budget = Math.max(0, budget - state.loop.used);
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Deterministic budget for an Orbit-owned run after PLAN is known.
|
|
88
|
+
* Small plans keep the historical floor of five; four/five-step plans gain two
|
|
89
|
+
* bounded recovery slots, with a hard automatic ceiling of seven.
|
|
90
|
+
*/
|
|
91
|
+
export function automaticLoopBudgetForPlan(stepCount) {
|
|
92
|
+
if (!Number.isSafeInteger(stepCount) || stepCount < MIN_PLAN_STEPS || stepCount > MAX_PLAN_STEPS) {
|
|
93
|
+
throw new Error(`ORBIT_PLAN_STEP_COUNT_INVALID: expected ${MIN_PLAN_STEPS}-${MAX_PLAN_STEPS}, got ${stepCount}`);
|
|
94
|
+
}
|
|
95
|
+
return Math.min(MAX_AUTOMATIC_LOOP_BUDGET, Math.max(DEFAULT_LOOP_BUDGET, stepCount + AUTOMATIC_LOOP_RECOVERY_RESERVE));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Expand only Orbit-owned automatic budgets. Explicit user/tool budgets and
|
|
99
|
+
* old states without a recorded mode are never silently increased.
|
|
100
|
+
*/
|
|
101
|
+
export function ensureAutomaticLoopBudgetForPlan(state) {
|
|
102
|
+
if (state.loop_budget_mode !== 'automatic')
|
|
103
|
+
return;
|
|
104
|
+
const baseSteps = state.plan.steps.filter((step) => isBaseStepId(step.id)).length;
|
|
105
|
+
const target = automaticLoopBudgetForPlan(baseSteps);
|
|
106
|
+
if (target > state.loop.max)
|
|
107
|
+
updateLoopBudget(state, target);
|
|
108
|
+
}
|
|
86
109
|
export function hashGoal(goal) {
|
|
87
110
|
let hash = 0;
|
|
88
111
|
for (let index = 0; index < goal.length; index += 1) {
|
|
@@ -123,8 +146,8 @@ export function correctionBlockCode(state, step) {
|
|
|
123
146
|
return undefined;
|
|
124
147
|
}
|
|
125
148
|
export function createInitialState(input) {
|
|
126
|
-
const
|
|
127
|
-
|
|
149
|
+
const explicit = explicitLoopBudget({ approved_loop_count: input.approvedLoopCount, max_loops: input.maxLoops });
|
|
150
|
+
const max = explicit ?? DEFAULT_LOOP_BUDGET;
|
|
128
151
|
return {
|
|
129
152
|
schema_version: ORBIT_SCHEMA_VERSION,
|
|
130
153
|
active_run_id: input.runId,
|
|
@@ -139,6 +162,7 @@ export function createInitialState(input) {
|
|
|
139
162
|
preset: input.preset ?? 'orbit-lite',
|
|
140
163
|
routes: structuredClone(input.routes),
|
|
141
164
|
loop: { used: 0, max },
|
|
165
|
+
loop_budget_mode: explicit === undefined ? 'automatic' : 'explicit',
|
|
142
166
|
approved_loop_count: max,
|
|
143
167
|
remaining_budget: max,
|
|
144
168
|
loop_count: 0,
|
package/lib/supervisor.js
CHANGED
|
@@ -2,7 +2,7 @@ import { join } from 'node:path';
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { buildEvidenceBundle, buildStepResult, formatStepResults, formatEvidenceBundle } from "./evidence.js";
|
|
4
4
|
import { assertCommanderDecision, assertStrategyDecision, assertTimeoutDecision, assertWatchdogDecision, assertGuardWatchdogDecision, COMMANDER_FINAL_EVALUATE_SCHEMA, COMMANDER_PLAN_SCHEMA, COMMANDER_STEP_EVALUATE_SCHEMA, COMMANDER_STRATEGY_SCHEMA, WATCHDOG_GUARD_SCHEMA, WATCHDOG_RUNTIME_SCHEMA, WATCHDOG_STRATEGY_SCHEMA, WATCHDOG_TIMEOUT_SCHEMA, } from "./decisions.js";
|
|
5
|
-
import { applyCommanderNeedsUser, applyCorrectionStep, applyExecutorCapabilityUnavailable, applyExecutorInterrupted, applyExecutorResume, applyExecutorSuccess, applyFinalAppend, applyFinalSuccess, applyPlan, applyStepPass, baseStepIdOf, beginStep, clearExecutorChild, clearGuardRecovery, correctionBlockCode, correctionDepthOf, createInitialState, enterBudgetExhausted, enterNeedsUser, markStrategyChallengeUsed, normalizePlan, openWatchdogAttempt, recordGuardRecovery, recordPlanFailure, recordWatchdogDecision, restoreEvaluationState, resumeFromNeedsUser, stopRun, upsertStepResult, normalizeCapabilities, } from "./kernel.js";
|
|
5
|
+
import { applyCommanderNeedsUser, applyCorrectionStep, applyExecutorCapabilityUnavailable, applyExecutorInterrupted, applyExecutorResume, applyExecutorSuccess, applyFinalAppend, applyFinalSuccess, applyPlan, applyStepPass, baseStepIdOf, beginStep, clearExecutorChild, clearGuardRecovery, correctionBlockCode, correctionDepthOf, createInitialState, enterBudgetExhausted, enterNeedsUser, ensureAutomaticLoopBudgetForPlan, markStrategyChallengeUsed, normalizePlan, openWatchdogAttempt, recordGuardRecovery, recordPlanFailure, recordWatchdogDecision, restoreEvaluationState, resumeFromNeedsUser, stopRun, upsertStepResult, normalizeCapabilities, } from "./kernel.js";
|
|
6
6
|
import { truncateSafe } from "./sanitize.js";
|
|
7
7
|
import { OrbitStateStore } from "./state-store.js";
|
|
8
8
|
import { executorToolsFor, EXECUTOR_READ_ONLY_TOOLS, READ_ONLY_ROLE_TOOLS } from "./capabilities.js";
|
|
@@ -305,6 +305,7 @@ export class OrbitSupervisor {
|
|
|
305
305
|
try {
|
|
306
306
|
const plan = normalizePlan(outcome.structured);
|
|
307
307
|
applyPlan(state, plan);
|
|
308
|
+
ensureAutomaticLoopBudgetForPlan(state);
|
|
308
309
|
this.store.writeState(state);
|
|
309
310
|
return undefined;
|
|
310
311
|
}
|
|
@@ -328,7 +329,7 @@ export class OrbitSupervisor {
|
|
|
328
329
|
return { kind: 'interrupted', reason: outcome.reason };
|
|
329
330
|
try {
|
|
330
331
|
const decision = assertCommanderDecision(outcome.structured, mode);
|
|
331
|
-
return { kind: 'decision', decision };
|
|
332
|
+
return { kind: 'decision', decision, output: outcome.output };
|
|
332
333
|
}
|
|
333
334
|
catch (error) {
|
|
334
335
|
// Invalid/temporary output is recoverable; it must not become NEEDS_USER.
|
|
@@ -387,7 +388,7 @@ export class OrbitSupervisor {
|
|
|
387
388
|
if (raced.value.structured === undefined) {
|
|
388
389
|
return { kind: 'interrupted', reason: `${mode}_STRUCTURED_OUTPUT_MISSING` };
|
|
389
390
|
}
|
|
390
|
-
return { kind: 'output', output: raced.value.output, structured: raced.value.structured };
|
|
391
|
+
return { kind: 'output', output: raced.value.visibleOutput ?? raced.value.output, structured: raced.value.structured };
|
|
391
392
|
}
|
|
392
393
|
if (raced.kind === 'aborted' || signal?.aborted) {
|
|
393
394
|
await this.cancelHandle(handle, 'ORBIT_ABORTED');
|
|
@@ -586,7 +587,7 @@ export class OrbitSupervisor {
|
|
|
586
587
|
if (decision.decision === 'SUCCESS') {
|
|
587
588
|
applyFinalSuccess(state, decision.summary);
|
|
588
589
|
this.store.writeState(state);
|
|
589
|
-
return this.result(state, true);
|
|
590
|
+
return this.result(state, true, undefined, outcome.output);
|
|
590
591
|
}
|
|
591
592
|
if (decision.decision === 'PASS_CURRENT_STEP') {
|
|
592
593
|
applyStepPass(state, step, decision.summary);
|
|
@@ -873,7 +874,7 @@ export class OrbitSupervisor {
|
|
|
873
874
|
return { ok: false, action: 'status', message: 'ORBIT_RUN_NOT_FOUND: 没有 Run 状态。' };
|
|
874
875
|
return this.result(state, true);
|
|
875
876
|
}
|
|
876
|
-
result(state, ok, message) {
|
|
877
|
+
result(state, ok, message, finalOutput) {
|
|
877
878
|
// Tool output must be lossless JSON: optional state fields are omitted, not
|
|
878
879
|
// emitted as `undefined`.
|
|
879
880
|
const data = {
|
|
@@ -896,6 +897,7 @@ export class OrbitSupervisor {
|
|
|
896
897
|
driver_ownership: state.driver_ownership,
|
|
897
898
|
state_revision: state.state_revision,
|
|
898
899
|
};
|
|
900
|
+
const displayText = state.phase === 'SUCCESS' ? finalOutput?.trim() || state.commander?.summary?.trim() : undefined;
|
|
899
901
|
return {
|
|
900
902
|
ok,
|
|
901
903
|
action: 'run',
|
|
@@ -903,6 +905,13 @@ export class OrbitSupervisor {
|
|
|
903
905
|
phase: state.phase,
|
|
904
906
|
status: state.status,
|
|
905
907
|
...(message ? { message } : {}),
|
|
908
|
+
...(displayText ? {
|
|
909
|
+
final_output: {
|
|
910
|
+
text: displayText,
|
|
911
|
+
provider: state.routes.commander.provider,
|
|
912
|
+
model: state.routes.commander.model,
|
|
913
|
+
},
|
|
914
|
+
} : {}),
|
|
906
915
|
data: Object.fromEntries(Object.entries(data).filter(([, value]) => value !== undefined)),
|
|
907
916
|
};
|
|
908
917
|
}
|
package/lib/types.js
CHANGED
|
@@ -13,6 +13,9 @@ export const MAX_EXECUTOR_INTERRUPT_RETRIES = 2;
|
|
|
13
13
|
export const MAX_PLAN_STEPS = 5;
|
|
14
14
|
export const MIN_PLAN_STEPS = 1;
|
|
15
15
|
export const DEFAULT_LOOP_BUDGET = 5;
|
|
16
|
+
/** Automatic runs reserve two bounded execution slots beyond the accepted base plan. */
|
|
17
|
+
export const AUTOMATIC_LOOP_RECOVERY_RESERVE = 2;
|
|
18
|
+
export const MAX_AUTOMATIC_LOOP_BUDGET = MAX_PLAN_STEPS + AUTOMATIC_LOOP_RECOVERY_RESERVE;
|
|
16
19
|
export const GUARD_FIRST_INSTRUCTION = '请改用更安全的方法继续当前任务,不要原样重试刚被阻断的操作。';
|
|
17
20
|
export const GUARD_REPEAT_INSTRUCTION = '同一操作再次被阻断。请停止重复,并选择不同的安全方案。';
|
|
18
21
|
export const GUARD_RETRY_INSTRUCTION = '之前的方案反复触发 Orbit 安全护栏。请改用不同的安全方案,不要重试被阻断的操作。';
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kasenri/dsh-orbit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "让 AI 项目可以在无人监管下持续推进。Orbit 会自动规划任务、分工执行、逐步检查并继续完成后续工作;不同环节可以使用不同模型,让低成本模型承担执行任务、强模型负责规划和审核,从而降低整体 AI 使用成本。Watchdog 还会监控运行异常,在任务卡死或中断时协助恢复。",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|