@siuver/omp-debug-mode 0.1.5 → 0.1.7
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/CHANGELOG.md +82 -48
- package/README.md +88 -31
- package/package.json +41 -41
- package/src/debug-mode.ts +285 -92
- package/src/evidence.ts +325 -169
- package/src/gate.ts +115 -51
- package/src/log-files.ts +161 -115
- package/src/machine.ts +136 -49
- package/src/main.ts +24 -24
- package/src/methodology.ts +56 -15
- package/src/state.ts +191 -42
- package/src/tools.ts +195 -9
- package/src/ui.ts +145 -71
package/src/machine.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseEvidencePlan } from "./evidence";
|
|
2
|
-
import { decideGate,
|
|
2
|
+
import { type GateFacts, MAX_HANDOFF_NUDGES, MAX_PROBE_NUDGES, decideGate, describeHandoff } from "./gate";
|
|
3
3
|
import {
|
|
4
4
|
CLEANUP_NUDGE,
|
|
5
5
|
buildFixedMessage,
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
type DebugState,
|
|
13
13
|
type EvidenceArtifact,
|
|
14
14
|
type EvidenceObservation,
|
|
15
|
+
type EvidenceRequest,
|
|
16
|
+
type HandoffMode,
|
|
15
17
|
type Probe,
|
|
16
18
|
type Round,
|
|
17
19
|
INACTIVE,
|
|
@@ -21,8 +23,10 @@ import {
|
|
|
21
23
|
declaresRuntimeProbe,
|
|
22
24
|
evidenceSummary,
|
|
23
25
|
freshSession,
|
|
24
|
-
|
|
26
|
+
liveProbeCount,
|
|
27
|
+
needsUserCapture,
|
|
25
28
|
pendingRequests,
|
|
29
|
+
roundProbeIds,
|
|
26
30
|
} from "./state";
|
|
27
31
|
|
|
28
32
|
export const PROMPT_START = "debug-mode-start";
|
|
@@ -32,14 +36,25 @@ export const PROMPT_FIXED = "debug-mode-fixed";
|
|
|
32
36
|
/** Artifact metadata gathered by the shell; the reducer only files it. */
|
|
33
37
|
export type ArtifactCandidate = Omit<EvidenceArtifact, "id" | "addedAt" | "requestId">;
|
|
34
38
|
|
|
39
|
+
/** No nudges left: used when there is no agent turn to send anything back to. */
|
|
40
|
+
const SPENT_NUDGES = { handoff: MAX_HANDOFF_NUDGES, probes: MAX_PROBE_NUDGES };
|
|
41
|
+
|
|
35
42
|
export type DebugEvent =
|
|
36
43
|
| { t: "start"; problem: string; debugDir: string; runId: string; logFile: string }
|
|
37
44
|
| { t: "turn_started" }
|
|
45
|
+
/** A user message landed in the transcript — the only thing that ends a user turn. */
|
|
46
|
+
| { t: "user_replied" }
|
|
38
47
|
| { t: "assistant_message"; text: string }
|
|
48
|
+
/** Any tool call: the progress signal the reminder guard waits for. */
|
|
49
|
+
| { t: "tool_used" }
|
|
39
50
|
| { t: "probes_found"; probes: Probe[] }
|
|
40
51
|
| { t: "ledger_synced"; probes: Probe[] }
|
|
41
52
|
| { t: "runs_observed"; runHistory: string[]; logCounts: Record<string, number> }
|
|
42
53
|
| { t: "turn_settled" }
|
|
54
|
+
/** An explicit `hand_off_to_user` call: intent the machine can trust. */
|
|
55
|
+
| { t: "handoff"; mode: HandoffMode; steps: string[]; plan: EvidenceRequest[] | null }
|
|
56
|
+
/** The user takes the turn back from a round that never settled. */
|
|
57
|
+
| { t: "reclaim" }
|
|
43
58
|
| { t: "proceed"; runId: string; logCount: number; hypotheses: string; details?: string; now: number }
|
|
44
59
|
| { t: "mark_fixed" }
|
|
45
60
|
| { t: "attach_artifact"; candidate: ArtifactCandidate; requestId: string | null; now: number }
|
|
@@ -94,18 +109,25 @@ export function reduce(state: DebugState, event: DebugEvent): Transition {
|
|
|
94
109
|
|
|
95
110
|
switch (event.t) {
|
|
96
111
|
case "turn_started":
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
// Deliberately stage-blind. A turn can start without the user doing
|
|
113
|
+
// anything — a todo reminder, a plan nudge or any other host
|
|
114
|
+
// continuation resumes the agent loop, which starts a turn while the
|
|
115
|
+
// round is still with the user. Reading "a turn began" as "the user
|
|
116
|
+
// replied" is what let those continuations take the user's turn away.
|
|
117
|
+
return session.turnProduced ? unchanged({ ...session, turnProduced: false }) : unchanged(session);
|
|
118
|
+
|
|
119
|
+
case "user_replied":
|
|
120
|
+
// A reply at a handoff hands the round back to the agent. Keeping the
|
|
121
|
+
// user stage through the turn would make the entire turn invisible to
|
|
122
|
+
// the machine and silently discard the plan and steps it produced.
|
|
123
|
+
return unchanged(session.stage === "user_turn" ? reopenRound(session) : session);
|
|
105
124
|
|
|
106
125
|
case "assistant_message":
|
|
107
126
|
return unchanged(absorbAssistantText(session, event.text));
|
|
108
127
|
|
|
128
|
+
case "tool_used":
|
|
129
|
+
return unchanged(clearNudgeWait(session));
|
|
130
|
+
|
|
109
131
|
case "probes_found": {
|
|
110
132
|
const fresh = event.probes.filter(probe => !session.probes.some(known => known.id === probe.id));
|
|
111
133
|
if (fresh.length === 0) return unchanged(session);
|
|
@@ -130,6 +152,12 @@ export function reduce(state: DebugState, event: DebugEvent): Transition {
|
|
|
130
152
|
case "turn_settled":
|
|
131
153
|
return settle(session);
|
|
132
154
|
|
|
155
|
+
case "handoff":
|
|
156
|
+
return applyHandoff(session, event);
|
|
157
|
+
|
|
158
|
+
case "reclaim":
|
|
159
|
+
return reclaim(session);
|
|
160
|
+
|
|
133
161
|
case "proceed":
|
|
134
162
|
return advance(session, event);
|
|
135
163
|
|
|
@@ -149,6 +177,31 @@ export function reduce(state: DebugState, event: DebugEvent): Transition {
|
|
|
149
177
|
}
|
|
150
178
|
}
|
|
151
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Give the round back to the agent. Nudge budgets are per agent turn rather
|
|
182
|
+
* than per round: a round the user replied to must still be repairable, or one
|
|
183
|
+
* spent budget would silence every later turn in the same round.
|
|
184
|
+
*/
|
|
185
|
+
function reopenRound(session: ActiveState): ActiveState {
|
|
186
|
+
const round = currentRound(session);
|
|
187
|
+
return withRound(
|
|
188
|
+
{ ...session, stage: "investigating", turnProduced: false },
|
|
189
|
+
{ ...round, handoff: null, nudges: { handoff: 0, probes: 0 }, awaitingProgress: false },
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Clear the reminder guard. A tool call means the agent acted on the reminder
|
|
195
|
+
* instead of restating itself, so the next settle may remind it again; a turn
|
|
196
|
+
* that only produces more prose keeps the guard set and is handed over.
|
|
197
|
+
*/
|
|
198
|
+
function clearNudgeWait(session: ActiveState): ActiveState {
|
|
199
|
+
if (session.stage !== "investigating") return session;
|
|
200
|
+
const round = currentRound(session);
|
|
201
|
+
if (!round.awaitingProgress) return session;
|
|
202
|
+
return withRound(session, { ...round, awaitingProgress: false });
|
|
203
|
+
}
|
|
204
|
+
|
|
152
205
|
/** Record the round artefacts a settled-but-not-yet-judged turn produced. */
|
|
153
206
|
function absorbAssistantText(session: ActiveState, text: string): ActiveState {
|
|
154
207
|
const round = currentRound(session);
|
|
@@ -157,70 +210,104 @@ function absorbAssistantText(session: ActiveState, text: string): ActiveState {
|
|
|
157
210
|
const next: Round = {
|
|
158
211
|
...round,
|
|
159
212
|
reproductionSteps: steps.length > 0 ? steps : round.reproductionSteps,
|
|
160
|
-
|
|
213
|
+
// A later malformed block must never erase a plan that already validated:
|
|
214
|
+
// the round would lose evidence requests the user was already shown.
|
|
215
|
+
plan: plan.valid ? plan.requests : round.plan,
|
|
161
216
|
};
|
|
162
217
|
const roundChanged = next.reproductionSteps !== round.reproductionSteps || next.plan !== round.plan;
|
|
163
218
|
if (!roundChanged) return session.turnProduced ? session : { ...session, turnProduced: true };
|
|
164
219
|
return withRound({ ...session, turnProduced: true }, next);
|
|
165
220
|
}
|
|
166
221
|
|
|
222
|
+
function gateFacts(session: ActiveState, round: Round): GateFacts {
|
|
223
|
+
return {
|
|
224
|
+
round: round.index,
|
|
225
|
+
hasReproductionSteps: round.reproductionSteps.length > 0,
|
|
226
|
+
hasEvidencePlan: round.plan !== null,
|
|
227
|
+
declaresRuntimeProbe: declaresRuntimeProbe(round),
|
|
228
|
+
needsUserCapture: needsUserCapture(round),
|
|
229
|
+
liveProbes: liveProbeCount(session),
|
|
230
|
+
probesAddedThisRound: roundProbeIds(session, round).length,
|
|
231
|
+
nudges: round.nudges,
|
|
232
|
+
awaitingProgress: round.awaitingProgress,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
167
236
|
function settle(session: ActiveState): Transition {
|
|
168
237
|
if (session.stage === "cleaning_up") return finishCleanup(session);
|
|
169
238
|
if (session.stage !== "investigating" || !session.turnProduced) return unchanged(session);
|
|
170
239
|
|
|
171
240
|
const round = currentRound(session);
|
|
172
|
-
const decision = decideGate(
|
|
173
|
-
hasReproductionSteps: round.reproductionSteps.length > 0,
|
|
174
|
-
hasEvidencePlan: round.plan !== null,
|
|
175
|
-
declaresRuntimeProbe: declaresRuntimeProbe(round),
|
|
176
|
-
liveProbes: liveProbeIds(session, round).length,
|
|
177
|
-
nudges: round.nudges,
|
|
178
|
-
});
|
|
241
|
+
const decision = decideGate(gateFacts(session, round));
|
|
179
242
|
|
|
180
243
|
if (decision.kind === "nudge") {
|
|
181
244
|
const nudges =
|
|
182
245
|
decision.budget === "probes"
|
|
183
246
|
? { ...round.nudges, probes: round.nudges.probes + 1 }
|
|
184
|
-
: { ...round.nudges,
|
|
247
|
+
: { ...round.nudges, handoff: round.nudges.handoff + 1 };
|
|
185
248
|
return {
|
|
186
|
-
state: withRound(session, { ...round, nudges }),
|
|
249
|
+
state: withRound(session, { ...round, nudges, awaitingProgress: true }),
|
|
187
250
|
effects: [{ kind: "continue", context: decision.context }],
|
|
188
251
|
};
|
|
189
252
|
}
|
|
190
253
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
state: withRound({ ...session, stage: "open" }, { ...round, openReason: decision.reason }),
|
|
194
|
-
effects: [
|
|
195
|
-
{
|
|
196
|
-
kind: "notify",
|
|
197
|
-
level: decision.reason === "awaiting_reply" ? "info" : "warning",
|
|
198
|
-
text: describeOpenReason(decision.reason, round.index),
|
|
199
|
-
},
|
|
200
|
-
],
|
|
201
|
-
};
|
|
202
|
-
}
|
|
254
|
+
return handOff(session, decision.mode, decision.missingPlan);
|
|
255
|
+
}
|
|
203
256
|
|
|
204
|
-
|
|
205
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Move the round to the user. Every settled turn ends here: the mode only
|
|
259
|
+
* changes the wording, so a mode the agent misjudged can never make a command
|
|
260
|
+
* illegal. The notify text leads with the same sentence as the widget so the
|
|
261
|
+
* transcript and the widget cannot disagree about whose move it is.
|
|
262
|
+
*/
|
|
263
|
+
function handOff(session: ActiveState, mode: HandoffMode, missingPlan: boolean): Transition {
|
|
264
|
+
const round = currentRound(session);
|
|
265
|
+
const next = withRound({ ...session, stage: "user_turn" }, { ...round, handoff: mode });
|
|
266
|
+
const pending = pendingRequests(next);
|
|
267
|
+
const detail = pending.length > 0 ? ` Pending: ${pending.map(request => request.id).join(", ")}.` : "";
|
|
268
|
+
return {
|
|
269
|
+
state: next,
|
|
270
|
+
effects: [
|
|
271
|
+
{
|
|
272
|
+
kind: "notify",
|
|
273
|
+
level: mode === "incomplete" || missingPlan ? "warning" : "info",
|
|
274
|
+
text: `${describeHandoff(mode, round.index, missingPlan)}${detail}`,
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
};
|
|
206
278
|
}
|
|
207
279
|
|
|
208
|
-
|
|
280
|
+
/**
|
|
281
|
+
* An explicit handoff call. The tool has already validated its arguments, so
|
|
282
|
+
* this records the declared plan and steps and hands over without consulting
|
|
283
|
+
* the gate: the agent said what it wants, and guessing from its prose is the
|
|
284
|
+
* failure mode the tool exists to remove.
|
|
285
|
+
*/
|
|
286
|
+
function applyHandoff(session: ActiveState, event: Extract<DebugEvent, { t: "handoff" }>): Transition {
|
|
287
|
+
if (session.stage !== "investigating") return unchanged(session);
|
|
209
288
|
const round = currentRound(session);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
289
|
+
const updated: Round = {
|
|
290
|
+
...round,
|
|
291
|
+
plan: event.plan ?? round.plan,
|
|
292
|
+
reproductionSteps: event.steps.length > 0 ? event.steps : round.reproductionSteps,
|
|
293
|
+
};
|
|
294
|
+
const staged = withRound({ ...session, turnProduced: true }, updated);
|
|
295
|
+
const expectsPlan = event.mode !== "question";
|
|
296
|
+
return handOff(staged, event.mode, expectsPlan && updated.plan === null);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Classify a round whose turn never settled. An aborted turn never reaches
|
|
301
|
+
* `session_stop`, so without this the stage would stay `investigating` and
|
|
302
|
+
* every debug command would refuse for the rest of the session.
|
|
303
|
+
*/
|
|
304
|
+
function reclaim(session: ActiveState): Transition {
|
|
305
|
+
if (session.stage !== "investigating") return unchanged(session);
|
|
306
|
+
const round = currentRound(session);
|
|
307
|
+
// There is no turn left to continue, so no nudge is available.
|
|
308
|
+
const decision = decideGate({ ...gateFacts(session, round), nudges: SPENT_NUDGES });
|
|
309
|
+
if (decision.kind === "nudge") return handOff(session, "incomplete", round.plan === null);
|
|
310
|
+
return handOff(session, decision.mode, decision.missingPlan);
|
|
224
311
|
}
|
|
225
312
|
|
|
226
313
|
/** Cleanup may only finish once the ledger is actually empty. */
|
package/src/main.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Debug Mode Extension — Cursor-style human-in-the-loop debugging for omp.
|
|
3
|
-
*
|
|
4
|
-
* State machine (matches Cursor Debug Mode):
|
|
5
|
-
* IDLE → /debug-mode <problem>
|
|
6
|
-
* → agent writes 3-5 hypotheses and @omp-probe instrumentation (no product fix)
|
|
7
|
-
* → WAITING_REPRO: agent stops; user reproduces out-of-band
|
|
8
|
-
* →
|
|
9
|
-
* with evidence, keeps probes, and asks for a verification reproduce → loop
|
|
10
|
-
* →
|
|
11
|
-
*
|
|
12
|
-
* - `state.ts` — persisted round state and the injected blackboard
|
|
13
|
-
* - `probes.ts` — `@omp-probe` ledger and its on-disk ground truth
|
|
14
|
-
* - `log-files.ts` — stable `<cwd>/.omp/debug/current.jsonl` and run archival
|
|
15
|
-
* - `methodology.ts` — the Cursor Debug Mode prompt contract
|
|
16
|
-
* - `debug-mode.ts` — state machine, commands, and lifecycle wiring
|
|
17
|
-
*/
|
|
18
|
-
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
19
|
-
import { registerDebugMode } from "./debug-mode";
|
|
20
|
-
|
|
21
|
-
export default function debugModeExtension(pi: ExtensionAPI) {
|
|
22
|
-
pi.setLabel("Debug Mode");
|
|
23
|
-
registerDebugMode(pi);
|
|
24
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Debug Mode Extension — Cursor-style human-in-the-loop debugging for omp.
|
|
3
|
+
*
|
|
4
|
+
* State machine (matches Cursor Debug Mode):
|
|
5
|
+
* IDLE → /debug-mode <problem>
|
|
6
|
+
* → agent writes 3-5 hypotheses and @omp-probe instrumentation (no product fix)
|
|
7
|
+
* → WAITING_REPRO: agent stops; user reproduces out-of-band
|
|
8
|
+
* → /debug-proceed [details] → agent reads logs, evaluates hypotheses, fixes only
|
|
9
|
+
* with evidence, keeps probes, and asks for a verification reproduce → loop
|
|
10
|
+
* → /debug-done → agent removes probes + summarizes → teardown (logs deleted)
|
|
11
|
+
*
|
|
12
|
+
* - `state.ts` — persisted round state and the injected blackboard
|
|
13
|
+
* - `probes.ts` — `@omp-probe` ledger and its on-disk ground truth
|
|
14
|
+
* - `log-files.ts` — stable `<cwd>/.omp/debug/current.jsonl` and run archival
|
|
15
|
+
* - `methodology.ts` — the Cursor Debug Mode prompt contract
|
|
16
|
+
* - `debug-mode.ts` — state machine, commands, and lifecycle wiring
|
|
17
|
+
*/
|
|
18
|
+
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
19
|
+
import { registerDebugMode } from "./debug-mode";
|
|
20
|
+
|
|
21
|
+
export default function debugModeExtension(pi: ExtensionAPI) {
|
|
22
|
+
pi.setLabel("Debug Mode");
|
|
23
|
+
registerDebugMode(pi);
|
|
24
|
+
}
|
package/src/methodology.ts
CHANGED
|
@@ -1,7 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The widget under the editor names every command already, so prose that
|
|
3
|
+
* repeats them is the same instruction three times on one screen: the call to
|
|
4
|
+
* action, the model's own closing line, and the actions strip all said
|
|
5
|
+
* `/debug-proceed`. A model told to "tell the user to run /debug-proceed" also
|
|
6
|
+
* writes it into `<reproduction_steps>`, where it becomes a numbered step the
|
|
7
|
+
* user cannot perform until every other step is done.
|
|
8
|
+
*/
|
|
9
|
+
export const COMMAND_ECHO_RULE =
|
|
10
|
+
"Do NOT name /debug-proceed or /debug-done in your closing prose or inside <reproduction_steps>: the widget " +
|
|
11
|
+
"under the user's editor already offers both, and repeating them puts the same instruction on screen three " +
|
|
12
|
+
"times. Close with one short line saying what to do — reproduce, capture, answer — never which command to type.";
|
|
2
13
|
|
|
3
14
|
export const EVIDENCE_PLAN_TAG = "evidence_plan";
|
|
4
15
|
|
|
16
|
+
/** The Agent tool that ends an agent turn and hands the round to the user. */
|
|
17
|
+
export const HANDOFF_TOOL = "hand_off_to_user";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Stated wherever a round is closed. Prose cannot move the session: the model
|
|
21
|
+
* announcing a reproduction is not the same event as the session reaching the
|
|
22
|
+
* user, and conflating them is what leaves a round unclosed while the user has
|
|
23
|
+
* already been told to act.
|
|
24
|
+
*/
|
|
25
|
+
export const HANDOFF_RULE =
|
|
26
|
+
`Close every round by calling ${HANDOFF_TOOL} as your last action. Pass mode ("reproduce" when the user must run ` +
|
|
27
|
+
'the app, "capture" when they only supply a report or file, "question" when you need an answer before you can ' +
|
|
28
|
+
"plan), the evidence plan array, and the numbered steps the USER performs now. That tool call is the only thing " +
|
|
29
|
+
"that hands the session to the user, and it replies with exactly what to fix when an argument is wrong, so a " +
|
|
30
|
+
`rejected call is repaired in this turn. <${EVIDENCE_PLAN_TAG}> and <reproduction_steps> in prose are still read ` +
|
|
31
|
+
"for their contents, but they never close a round: a turn that stops without the tool call is sent straight back " +
|
|
32
|
+
"to you to make it.";
|
|
33
|
+
|
|
5
34
|
/** The least-user-intervention evidence method ordering, verbatim for prompts. */
|
|
6
35
|
export const MINIMIZE_USER_INTERVENTION =
|
|
7
36
|
"MINIMIZE USER INTERVENTION. Choose the cheapest reliable evidence method per hypothesis, in this exact order: " +
|
|
@@ -60,9 +89,10 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
60
89
|
- The extension truncates the current log file at the start of each round.
|
|
61
90
|
Do not delete, rename, or overwrite that file yourself.
|
|
62
91
|
|
|
63
|
-
4. Close the round only after step 3 is done for any runtime_probe plan.
|
|
64
|
-
|
|
65
|
-
non-empty JSON array covering EVERY hypothesis
|
|
92
|
+
4. Close the round only after step 3 is done for any runtime_probe plan.
|
|
93
|
+
${HANDOFF_RULE}
|
|
94
|
+
The plan is a non-empty JSON array covering EVERY hypothesis, in the same
|
|
95
|
+
shape accepted inside a legacy <${EVIDENCE_PLAN_TAG}> block:
|
|
66
96
|
<${EVIDENCE_PLAN_TAG}>
|
|
67
97
|
[{"id":"E1","hypothesisIds":["A","B"],"method":"runtime_probe","title":"...","rationale":"The disputed runtime branches are not present in existing logs; one model-added probe set can capture both without a separate user artifact.","instructions":["..."],"artifactHint":"optional"}]
|
|
68
98
|
</${EVIDENCE_PLAN_TAG}>
|
|
@@ -70,18 +100,22 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
70
100
|
Use artifactHint only for user_artifact (expected file kind). Give actionable
|
|
71
101
|
numbered capture/report instructions in instructions.
|
|
72
102
|
|
|
73
|
-
5. Ask the user to reproduce (or capture/report, per the plan).
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
5. Ask the user to reproduce (or capture/report, per the plan). Pass the single
|
|
104
|
+
combined reproduction/capture sequence the USER performs now as the steps
|
|
105
|
+
argument of ${HANDOFF_TOOL} — the widget the user reads is built from that
|
|
106
|
+
call, not from your prose. A <reproduction_steps> numbered list (no header
|
|
107
|
+
inside the tag) is read as content but closes nothing, so make the call even
|
|
108
|
+
when you also wrote the prose.
|
|
77
109
|
${CLOSE_ROUND_RULES}
|
|
78
|
-
|
|
79
|
-
|
|
110
|
+
${COMMAND_ECHO_RULE}
|
|
111
|
+
Never say "click" or "press Proceed": those buttons do not exist, and never
|
|
112
|
+
ask the user to reply "done". Remind them to restart the app or service if
|
|
113
|
+
the instrumented code would otherwise be stale.
|
|
80
114
|
Then STOP. The user reproduces out-of-band.
|
|
81
115
|
No logs may be expected for user_report/user_artifact plans: evaluate the
|
|
82
116
|
requested user evidence instead of treating absent probes as a failed round.
|
|
83
117
|
|
|
84
|
-
6. After
|
|
118
|
+
6. After /debug-proceed: call list_debug_evidence, then read logs with get_debug_logs
|
|
85
119
|
(previous=true for the completed run). Evaluate EACH hypothesis as CONFIRMED,
|
|
86
120
|
REJECTED, or INCONCLUSIVE citing the selected evidence method: hypothesis ID
|
|
87
121
|
plus log-line numbers, a submitted observation, or an attached artifact/report
|
|
@@ -98,7 +132,7 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
98
132
|
8. After a fix, ask the user to reproduce again. Compare before/after logs with
|
|
99
133
|
cited entries. Do not claim success without that proof.
|
|
100
134
|
|
|
101
|
-
9. If verification proves success and the user
|
|
135
|
+
9. If verification proves success and the user runs /debug-done: remove
|
|
102
136
|
every probe, verify with list_debug_probes that the ledger is empty, then
|
|
103
137
|
summarize the root cause and the final fix in 1-2 lines.
|
|
104
138
|
|
|
@@ -121,9 +155,12 @@ export function buildStartMessage(problem: string, logFile: string): string {
|
|
|
121
155
|
"Begin round 1: generate 3-5 precise hypotheses, decide an evidence method for each, and do NOT apply a product fix yet. " +
|
|
122
156
|
CLOSE_ROUND_RULES +
|
|
123
157
|
" " +
|
|
158
|
+
HANDOFF_RULE +
|
|
159
|
+
" " +
|
|
124
160
|
"Call list_debug_evidence whenever you need the request/observation/artifact ledger. " +
|
|
125
161
|
"Cite evidence as hypothesis ID plus log-line number or attached observation/artifact/report path. " +
|
|
126
|
-
`Then close with
|
|
162
|
+
`Then close with ${HANDOFF_TOOL} — prose alone never closes a round, so make the call even if you also wrote ` +
|
|
163
|
+
`a <${EVIDENCE_PLAN_TAG}> block. ${COMMAND_ECHO_RULE} Then STOP.`
|
|
127
164
|
);
|
|
128
165
|
}
|
|
129
166
|
|
|
@@ -158,7 +195,9 @@ export function buildProceedMessage(args: {
|
|
|
158
195
|
"If a previous fix failed, first revert code changes from rejected hypotheses. " +
|
|
159
196
|
CLOSE_ROUND_RULES +
|
|
160
197
|
" " +
|
|
161
|
-
|
|
198
|
+
HANDOFF_RULE +
|
|
199
|
+
" " +
|
|
200
|
+
`Then end with ${HANDOFF_TOOL} — prose alone never closes a round. ${COMMAND_ECHO_RULE} Then STOP.`
|
|
162
201
|
);
|
|
163
202
|
}
|
|
164
203
|
|
|
@@ -174,7 +213,9 @@ The user confirmed the fix. Only two things remain:
|
|
|
174
213
|
\`#region agent log\` wrapper, then call list_debug_probes and confirm the
|
|
175
214
|
ledger is empty. Keep the proven fix; remove nothing else.
|
|
176
215
|
2. Summarize in 1-2 lines: the root cause and the fix that is staying.
|
|
177
|
-
Do not add probes, form new hypotheses, or ask for another reproduction
|
|
216
|
+
Do not add probes, form new hypotheses, or ask for another reproduction, and do
|
|
217
|
+
not call ${HANDOFF_TOOL}: cleanup ends when the ledger is empty and you have
|
|
218
|
+
summarized.`;
|
|
178
219
|
|
|
179
220
|
/** Sent back into a cleanup turn that ended with probes still in the code. */
|
|
180
221
|
export const CLEANUP_NUDGE =
|