sortie-dogs 0.10.9 → 0.10.11
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/dist/asset-version.d.ts +1 -1
- package/dist/asset-version.js +1 -1
- package/dist/core/operator-proposal.d.ts +19 -0
- package/dist/core/operator-proposal.js +24 -1
- package/dist/plugin/config.js +1 -1
- package/dist/plugin/index.js +5 -0
- package/dist/plugin/profiled.js +16 -7
- package/dist/runtime-assets-v010.js +1 -1
- package/package.json +1 -1
package/dist/asset-version.d.ts
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export declare const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export declare const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1";
|
|
6
|
+
export declare const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1";
|
|
7
7
|
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1";
|
|
6
|
+
export const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1";
|
|
@@ -86,6 +86,24 @@ export interface OperatorProposalState {
|
|
|
86
86
|
proposal: OperatorProposalPacket | null;
|
|
87
87
|
approval_rationale: string | null;
|
|
88
88
|
}
|
|
89
|
+
export interface OperatorProposalBudgetDiagnostic {
|
|
90
|
+
readonly status: "proposal-budget-exhausted";
|
|
91
|
+
readonly code: "operator-proposal-read-budget-exhausted" | "operator-proposal-submission-budget-exhausted";
|
|
92
|
+
readonly reads: number;
|
|
93
|
+
readonly max_reads: number;
|
|
94
|
+
readonly remaining_reads: number;
|
|
95
|
+
readonly submissions: number;
|
|
96
|
+
readonly max_submissions: number;
|
|
97
|
+
readonly remaining_submissions: number;
|
|
98
|
+
readonly required_minimum_budget: {
|
|
99
|
+
readonly max_reads: number;
|
|
100
|
+
readonly max_submissions: number;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export declare class OperatorProposalBudgetError extends Error {
|
|
104
|
+
readonly diagnostic: OperatorProposalBudgetDiagnostic;
|
|
105
|
+
constructor(diagnostic: OperatorProposalBudgetDiagnostic);
|
|
106
|
+
}
|
|
89
107
|
/** Durable pre-execution lane. It grants investigation and submission, never source mutation or execution. */
|
|
90
108
|
export declare class OperatorProposalRuntime {
|
|
91
109
|
readonly profile: RuntimeProfile;
|
|
@@ -101,6 +119,7 @@ export declare class OperatorProposalRuntime {
|
|
|
101
119
|
read(root: string): Promise<OperatorProposalState | undefined>;
|
|
102
120
|
private readUnlocked;
|
|
103
121
|
private save;
|
|
122
|
+
private assertBudgetAvailable;
|
|
104
123
|
task(state: OperatorProposalState): OperatorTask;
|
|
105
124
|
/** Root-visible bounded handle; the canonical prompt remains only in durable host state. */
|
|
106
125
|
referenceTask(state: OperatorProposalState): OperatorTask;
|
|
@@ -93,6 +93,13 @@ const normalizedRelativePath = (value) => {
|
|
|
93
93
|
return false;
|
|
94
94
|
}
|
|
95
95
|
};
|
|
96
|
+
export class OperatorProposalBudgetError extends Error {
|
|
97
|
+
diagnostic;
|
|
98
|
+
constructor(diagnostic) {
|
|
99
|
+
super(diagnostic.code);
|
|
100
|
+
this.diagnostic = diagnostic;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
96
103
|
function parseIntent(value) {
|
|
97
104
|
const proposalBudget = record(value) && Object.hasOwn(value, "proposal_budget")
|
|
98
105
|
? value.proposal_budget
|
|
@@ -366,6 +373,18 @@ export class OperatorProposalRuntime {
|
|
|
366
373
|
}
|
|
367
374
|
this.states.set(state.root_session_id, structuredClone(state));
|
|
368
375
|
}
|
|
376
|
+
assertBudgetAvailable(state) {
|
|
377
|
+
const remainingReads = state.intent.proposal_budget.max_reads - state.read_count;
|
|
378
|
+
const remainingSubmissions = state.intent.proposal_budget.max_submissions - state.submission_count;
|
|
379
|
+
if (remainingReads > 0 && remainingSubmissions > 0)
|
|
380
|
+
return;
|
|
381
|
+
throw new OperatorProposalBudgetError({ status: "proposal-budget-exhausted",
|
|
382
|
+
code: remainingReads <= 0 ? "operator-proposal-read-budget-exhausted" : "operator-proposal-submission-budget-exhausted",
|
|
383
|
+
reads: state.read_count, max_reads: state.intent.proposal_budget.max_reads, remaining_reads: Math.max(0, remainingReads),
|
|
384
|
+
submissions: state.submission_count, max_submissions: state.intent.proposal_budget.max_submissions,
|
|
385
|
+
remaining_submissions: Math.max(0, remainingSubmissions),
|
|
386
|
+
required_minimum_budget: { max_reads: state.read_count + 1, max_submissions: state.submission_count + 1 } });
|
|
387
|
+
}
|
|
369
388
|
task(state) {
|
|
370
389
|
return { subagent_type: this.profile.agentNames["dog-operator"], description: "承認前の調査と実行契約案作成",
|
|
371
390
|
prompt: [`SORTIE_OPERATOR_PROPOSAL ${JSON.stringify({ root: state.root_session_id, intent_id: state.intent_id, intent_hash: state.intent_hash })}`,
|
|
@@ -435,8 +454,10 @@ export class OperatorProposalRuntime {
|
|
|
435
454
|
async beginUnlocked(root, raw) {
|
|
436
455
|
const intent = parseIntent(raw), intentHash = hash(JSON.stringify(intent)), previous = await this.readUnlocked(root);
|
|
437
456
|
if (previous) {
|
|
438
|
-
if (previous.intent_hash === intentHash)
|
|
457
|
+
if (previous.intent_hash === intentHash) {
|
|
458
|
+
this.assertBudgetAvailable(previous);
|
|
439
459
|
return previous;
|
|
460
|
+
}
|
|
440
461
|
if (previous.phase !== "approved")
|
|
441
462
|
throw new Error("operator-proposal-active-intent-immutable");
|
|
442
463
|
throw new Error("operator-proposal-new-intent-requires-explicit-root-revision");
|
|
@@ -446,6 +467,7 @@ export class OperatorProposalRuntime {
|
|
|
446
467
|
intent_id: `intent-${intentHash.slice(0, 24)}`, intent_hash: intentHash, intent, created_at: new Date().toISOString(), phase: "investigating",
|
|
447
468
|
goal_binding: null, proposal_call_id: null, proposal_session_id: null, read_count: spend.reads, read_paths: [], submission_count: spend.submissions, proposal_id: null,
|
|
448
469
|
proposal_revision: null, proposal_hash: null, proposal: null, approval_rationale: null };
|
|
470
|
+
this.assertBudgetAvailable(state);
|
|
449
471
|
await this.save(state);
|
|
450
472
|
return state;
|
|
451
473
|
}
|
|
@@ -474,6 +496,7 @@ export class OperatorProposalRuntime {
|
|
|
474
496
|
const state = await this.requiredUnlocked(root);
|
|
475
497
|
if (state.phase !== "investigating" || state.proposal_call_id !== null)
|
|
476
498
|
throw new Error("operator-proposal-dispatch-not-authorized");
|
|
499
|
+
this.assertBudgetAvailable(state);
|
|
477
500
|
const canonical = this.resolveTask(state, args);
|
|
478
501
|
// Reserve only after the grant check, while competing admissions remain queued.
|
|
479
502
|
await reserveBudget?.();
|
package/dist/plugin/config.js
CHANGED
|
@@ -33,7 +33,7 @@ export const DEFAULT_PLUGIN_OPTIONS = {
|
|
|
33
33
|
capability: CONTINUATION_CAPABILITY,
|
|
34
34
|
taskWatchdogMilliseconds: DEFAULT_TASK_WATCHDOG_MILLISECONDS,
|
|
35
35
|
}),
|
|
36
|
-
reflection: Object.freeze({ enabled:
|
|
36
|
+
reflection: Object.freeze({ enabled: true, layers: Object.freeze({ run: true, project: true, global: true }), maxInjectedEntries: 3, maxInjectedTokens: 500 }),
|
|
37
37
|
validationProfile: "balanced",
|
|
38
38
|
};
|
|
39
39
|
function isRecord(value) {
|
package/dist/plugin/index.js
CHANGED
|
@@ -7573,6 +7573,10 @@ export const SortieDogsPlugin = async (input, options) => {
|
|
|
7573
7573
|
registerGoalDeclaration: async (root, prompt) => {
|
|
7574
7574
|
if (!isCoordinatorSession(root) && !await recoverCoordinatorRoot(root))
|
|
7575
7575
|
throw new Error("operator-coordinator-required");
|
|
7576
|
+
// In one-shot CLI turns OpenCode may persist the user message only after chat.message returns.
|
|
7577
|
+
// Proposal preparation can reach registration first, so recover that exact pending real turn here
|
|
7578
|
+
// instead of freezing a prepared contract that can never consume its user revision authority.
|
|
7579
|
+
await recoverPendingRealGoalTurn(root);
|
|
7576
7580
|
const registered = await bindGoalDeclaration(root, prompt);
|
|
7577
7581
|
if (registered?.goal_id === null || registered === undefined)
|
|
7578
7582
|
throw new Error("operator-goal-registration-unavailable");
|
|
@@ -7588,6 +7592,7 @@ export const SortieDogsPlugin = async (input, options) => {
|
|
|
7588
7592
|
relinkRegisteredGoal: async (root, request) => {
|
|
7589
7593
|
if (!isCoordinatorSession(root) && !await recoverCoordinatorRoot(root))
|
|
7590
7594
|
throw new Error("operator-coordinator-required");
|
|
7595
|
+
await recoverPendingRealGoalTurn(root);
|
|
7591
7596
|
await recoverCompletedGoalReservations(root);
|
|
7592
7597
|
const ledger = await goalLedger(root), snapshot = await ledger.readGoal(), state = snapshot.state;
|
|
7593
7598
|
if (state.phase !== "active" || state.receipt !== null)
|
package/dist/plugin/profiled.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { V010_RUNTIME_ASSET_VERSION } from "../asset-version.js";
|
|
2
2
|
import { OperatorContractError, OperatorRuntime } from "../core/operator-runtime.js";
|
|
3
|
-
import { DEFAULT_OPERATOR_PROPOSAL_BUDGET, OPERATOR_APPROVAL_CONTRACT, OPERATOR_PROPOSAL_BUDGET_CAPS, OperatorProposalRuntime } from "../core/operator-proposal.js";
|
|
3
|
+
import { DEFAULT_OPERATOR_PROPOSAL_BUDGET, OPERATOR_APPROVAL_CONTRACT, OPERATOR_PROPOSAL_BUDGET_CAPS, OperatorProposalBudgetError, OperatorProposalRuntime } from "../core/operator-proposal.js";
|
|
4
4
|
import { CANONICAL_AGENT_ROLES, canonicalAgent, profileAgent, profileTool, V010_RUNTIME_PROFILE } from "../core/runtime-profile.js";
|
|
5
5
|
import { SortieDogsPlugin as canonicalPlugin } from "./index.js";
|
|
6
6
|
import { taskChildSessionID } from "./task-result-repair.js";
|
|
@@ -40,7 +40,7 @@ const PREVIEW_ROUTES = Object.freeze([
|
|
|
40
40
|
]);
|
|
41
41
|
export function processRemediationReplacementPacket(code, packet, cancelTool, prepareTool) {
|
|
42
42
|
return { status: "operator-process-remediation-replacement-required", code, packet,
|
|
43
|
-
next_action: `Call ${cancelTool}
|
|
43
|
+
next_action: `Call ${cancelTool} with reason=plain, then call ${prepareTool} with the exact same ordered acceptance, ` +
|
|
44
44
|
"the same unit and write scope, and the remaining cumulative budget. Do not call resume_operator again, " +
|
|
45
45
|
"claim evidence, reset spend, or widen scope." };
|
|
46
46
|
}
|
|
@@ -546,7 +546,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
546
546
|
const proposal = await proposals.read(context.sessionID);
|
|
547
547
|
const proposalNextAction = proposal?.phase === "investigating"
|
|
548
548
|
? proposal.proposal_call_id !== null
|
|
549
|
-
? "proposal Task is already admitted; do not redispatch it or call operator_next. Continue submission repairs only in the same active claimed child. If that child terminated without submission, report the terminal proposal failure; remaining read or submission capacity does not authorize a new Task, budget reset, or replacement child. Only an explicit root decision to retry may call cancel_operator with
|
|
549
|
+
? "proposal Task is already admitted; do not redispatch it or call operator_next. Continue submission repairs only in the same active claimed child. If that child terminated without submission, report the terminal proposal failure; remaining read or submission capacity does not authorize a new Task, budget reset, or replacement child. Only an explicit root decision to retry may call cancel_operator with reason=plain to release this grant, which discards the spent proposal accounting and never reuses the terminated child"
|
|
550
550
|
: proposal.submission_count >= proposal.intent.proposal_budget.max_submissions
|
|
551
551
|
? "proposal submission budget exhausted; do not call operator_next; report the bounded proposal failure"
|
|
552
552
|
: "proposal is not submitted; do not call operator_next; complete or repair the bounded proposal submission"
|
|
@@ -562,10 +562,11 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
562
562
|
next_action: proposalNextAction }
|
|
563
563
|
: { status: "absent", profile: profile.id });
|
|
564
564
|
} };
|
|
565
|
-
tools[cancel] = { description: "Revoke this root's operator grant and stop only its owned children before releasing core state. Before approval it instead releases the bounded proposal grant, including one whose admitted child already terminated, so the root can begin a new investigation; it never reuses that child or restores spent proposal budget. reason is a closed set:
|
|
566
|
-
args: { reason:
|
|
565
|
+
tools[cancel] = { description: "Revoke this root's operator grant and stop only its owned children before releasing core state. Before approval it instead releases the bounded proposal grant, including one whose admitted child already terminated, so the root can begin a new investigation; it never reuses that child or restores spent proposal budget. reason is a required closed set: use reason=plain for a plain cancellation, including replanning, contract revision, and any pre-approval proposal release, and never send free text such as a written justification. Use reason=acceptance-remediation only for decision=operator-acceptance-remediation-required. At awaiting-acceptance, reason=review-blocking authorizes a same-goal review-remediation replacement only within the exact acceptance, committed head, approved write union, and retained remaining budget.",
|
|
566
|
+
args: { reason: { type: "string", enum: ["plain", "review-blocking", "acceptance-remediation"] } }, execute: async (args, context) => {
|
|
567
567
|
await requireRoot(context.sessionID);
|
|
568
|
-
const
|
|
568
|
+
const rawReason = args.reason;
|
|
569
|
+
const requestedReason = rawReason === "plain" || rawReason === undefined ? undefined : rawReason;
|
|
569
570
|
if (requestedReason !== undefined && requestedReason !== "review-blocking" && requestedReason !== "acceptance-remediation")
|
|
570
571
|
throw new Error("operator-cancel-reason-invalid");
|
|
571
572
|
const pending = await operators.read(context.sessionID);
|
|
@@ -759,7 +760,15 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
759
760
|
tools[beginProposal] = { description: `Root-only: freeze original ordered requirements and grant one bounded read-only proposal investigation to dogs-coordinator. The result contains one exact short Task reference; pass task.subagent_type, task.description, and task.prompt byte-for-byte without appending or paraphrasing. The native parent retains that reference; the host expands it only inside the directly claimed proposal child. ${OPERATOR_INTENT_CONTRACT}`,
|
|
760
761
|
args: { intent_json: intentSchema }, execute: async (args, context) => {
|
|
761
762
|
await requireRoot(context.sessionID);
|
|
762
|
-
let state
|
|
763
|
+
let state;
|
|
764
|
+
try {
|
|
765
|
+
state = await proposals.begin(context.sessionID, JSON.parse(args.intent_json));
|
|
766
|
+
}
|
|
767
|
+
catch (error) {
|
|
768
|
+
if (error instanceof OperatorProposalBudgetError)
|
|
769
|
+
return JSON.stringify(error.diagnostic);
|
|
770
|
+
throw error;
|
|
771
|
+
}
|
|
763
772
|
state = await proposals.bindGoal(context.sessionID, await control.proposalGoalBinding(context.sessionID));
|
|
764
773
|
return JSON.stringify({ ...proposals.packet(state), task: proposals.referenceTask(state),
|
|
765
774
|
dispatch_instruction: "Pass this short Task reference verbatim; do not append or paraphrase it." });
|
|
@@ -157,7 +157,7 @@ budgets or your own reporting obligations into worker validation commands. Prese
|
|
|
157
157
|
That child remains the same logical operations role: it may inspect only the host-approved read prefixes and submit one
|
|
158
158
|
requirement-mapped proposal; it cannot edit, use shell, dispatch a worker/advisor/scout, widen read scope, or execute work.
|
|
159
159
|
An admitted proposal child is never redispatched or replaced. If it terminates without a submitted proposal, report that
|
|
160
|
-
terminal failure first; only an explicit decision to retry may call ${profile.toolPrefix}cancel_operator with
|
|
160
|
+
terminal failure first; only an explicit decision to retry may call ${profile.toolPrefix}cancel_operator with reason=plain to
|
|
161
161
|
release the grant before freezing the requirements again. Spent proposal reads and submissions are never restored.
|
|
162
162
|
Do not cancel/reinvestigate the same known contract defect merely to get another draft. Preserve exact observed
|
|
163
163
|
commands and correction evidence. If a user-only acceptance condition cannot be expressed by the existing contract,
|