@siuver/omp-debug-mode 0.1.5 → 0.1.6
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 +73 -48
- package/README.md +84 -31
- package/package.json +41 -41
- package/src/debug-mode.ts +240 -92
- package/src/evidence.ts +325 -169
- package/src/gate.ts +115 -51
- package/src/log-files.ts +154 -115
- package/src/machine.ts +136 -49
- package/src/main.ts +24 -24
- package/src/methodology.ts +46 -15
- package/src/state.ts +191 -42
- package/src/tools.ts +195 -9
- package/src/ui.ts +109 -69
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,26 @@
|
|
|
1
|
-
export const PROCEED_REMINDER =
|
|
1
|
+
export const PROCEED_REMINDER =
|
|
2
|
+
"When done, run /debug-proceed to analyze this round, or /debug-done if the bug is fixed.";
|
|
2
3
|
|
|
3
4
|
export const EVIDENCE_PLAN_TAG = "evidence_plan";
|
|
4
5
|
|
|
6
|
+
/** The Agent tool that ends an agent turn and hands the round to the user. */
|
|
7
|
+
export const HANDOFF_TOOL = "hand_off_to_user";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Stated wherever a round is closed. Prose cannot move the session: the model
|
|
11
|
+
* announcing a reproduction is not the same event as the session reaching the
|
|
12
|
+
* user, and conflating them is what leaves a round unclosed while the user has
|
|
13
|
+
* already been told to act.
|
|
14
|
+
*/
|
|
15
|
+
export const HANDOFF_RULE =
|
|
16
|
+
`Close every round by calling ${HANDOFF_TOOL} as your last action. Pass mode ("reproduce" when the user must run ` +
|
|
17
|
+
'the app, "capture" when they only supply a report or file, "question" when you need an answer before you can ' +
|
|
18
|
+
"plan), the evidence plan array, and the numbered steps the USER performs now. That tool call is the only thing " +
|
|
19
|
+
"that hands the session to the user, and it replies with exactly what to fix when an argument is wrong, so a " +
|
|
20
|
+
`rejected call is repaired in this turn. <${EVIDENCE_PLAN_TAG}> and <reproduction_steps> in prose are still read ` +
|
|
21
|
+
"for their contents, but they never close a round: a turn that stops without the tool call is sent straight back " +
|
|
22
|
+
"to you to make it.";
|
|
23
|
+
|
|
5
24
|
/** The least-user-intervention evidence method ordering, verbatim for prompts. */
|
|
6
25
|
export const MINIMIZE_USER_INTERVENTION =
|
|
7
26
|
"MINIMIZE USER INTERVENTION. Choose the cheapest reliable evidence method per hypothesis, in this exact order: " +
|
|
@@ -60,9 +79,10 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
60
79
|
- The extension truncates the current log file at the start of each round.
|
|
61
80
|
Do not delete, rename, or overwrite that file yourself.
|
|
62
81
|
|
|
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
|
|
82
|
+
4. Close the round only after step 3 is done for any runtime_probe plan.
|
|
83
|
+
${HANDOFF_RULE}
|
|
84
|
+
The plan is a non-empty JSON array covering EVERY hypothesis, in the same
|
|
85
|
+
shape accepted inside a legacy <${EVIDENCE_PLAN_TAG}> block:
|
|
66
86
|
<${EVIDENCE_PLAN_TAG}>
|
|
67
87
|
[{"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
88
|
</${EVIDENCE_PLAN_TAG}>
|
|
@@ -70,18 +90,22 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
70
90
|
Use artifactHint only for user_artifact (expected file kind). Give actionable
|
|
71
91
|
numbered capture/report instructions in instructions.
|
|
72
92
|
|
|
73
|
-
5. Ask the user to reproduce (or capture/report, per the plan).
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
5. Ask the user to reproduce (or capture/report, per the plan). Pass the single
|
|
94
|
+
combined reproduction/capture sequence the USER performs now as the steps
|
|
95
|
+
argument of ${HANDOFF_TOOL} — the widget the user reads is built from that
|
|
96
|
+
call, not from your prose. A <reproduction_steps> numbered list (no header
|
|
97
|
+
inside the tag) followed by "${PROCEED_REMINDER}" is read as content but
|
|
98
|
+
closes nothing, so make the call even when you also wrote the prose.
|
|
77
99
|
${CLOSE_ROUND_RULES}
|
|
78
|
-
Never say "click"
|
|
79
|
-
|
|
100
|
+
Never say "click" or "press Proceed": those buttons do not exist. Name
|
|
101
|
+
/debug-proceed and /debug-done by those exact commands. Never ask the user to
|
|
102
|
+
reply "done". Remind them to restart the app or service if the instrumented
|
|
103
|
+
code would otherwise be stale.
|
|
80
104
|
Then STOP. The user reproduces out-of-band.
|
|
81
105
|
No logs may be expected for user_report/user_artifact plans: evaluate the
|
|
82
106
|
requested user evidence instead of treating absent probes as a failed round.
|
|
83
107
|
|
|
84
|
-
6. After
|
|
108
|
+
6. After /debug-proceed: call list_debug_evidence, then read logs with get_debug_logs
|
|
85
109
|
(previous=true for the completed run). Evaluate EACH hypothesis as CONFIRMED,
|
|
86
110
|
REJECTED, or INCONCLUSIVE citing the selected evidence method: hypothesis ID
|
|
87
111
|
plus log-line numbers, a submitted observation, or an attached artifact/report
|
|
@@ -98,7 +122,7 @@ This is OMP Debug Mode. Follow the steps in order. Do not skip them.
|
|
|
98
122
|
8. After a fix, ask the user to reproduce again. Compare before/after logs with
|
|
99
123
|
cited entries. Do not claim success without that proof.
|
|
100
124
|
|
|
101
|
-
9. If verification proves success and the user
|
|
125
|
+
9. If verification proves success and the user runs /debug-done: remove
|
|
102
126
|
every probe, verify with list_debug_probes that the ledger is empty, then
|
|
103
127
|
summarize the root cause and the final fix in 1-2 lines.
|
|
104
128
|
|
|
@@ -121,9 +145,12 @@ export function buildStartMessage(problem: string, logFile: string): string {
|
|
|
121
145
|
"Begin round 1: generate 3-5 precise hypotheses, decide an evidence method for each, and do NOT apply a product fix yet. " +
|
|
122
146
|
CLOSE_ROUND_RULES +
|
|
123
147
|
" " +
|
|
148
|
+
HANDOFF_RULE +
|
|
149
|
+
" " +
|
|
124
150
|
"Call list_debug_evidence whenever you need the request/observation/artifact ledger. " +
|
|
125
151
|
"Cite evidence as hypothesis ID plus log-line number or attached observation/artifact/report path. " +
|
|
126
|
-
`Then close with
|
|
152
|
+
`Then close with ${HANDOFF_TOOL} — prose alone never closes a round, so make the call even if you also wrote ` +
|
|
153
|
+
`a <${EVIDENCE_PLAN_TAG}> block — tell the user "${PROCEED_REMINDER}" and STOP.`
|
|
127
154
|
);
|
|
128
155
|
}
|
|
129
156
|
|
|
@@ -158,7 +185,9 @@ export function buildProceedMessage(args: {
|
|
|
158
185
|
"If a previous fix failed, first revert code changes from rejected hypotheses. " +
|
|
159
186
|
CLOSE_ROUND_RULES +
|
|
160
187
|
" " +
|
|
161
|
-
|
|
188
|
+
HANDOFF_RULE +
|
|
189
|
+
" " +
|
|
190
|
+
`Then end with ${HANDOFF_TOOL} — prose alone never closes a round — tell the user "${PROCEED_REMINDER}" and STOP.`
|
|
162
191
|
);
|
|
163
192
|
}
|
|
164
193
|
|
|
@@ -174,7 +203,9 @@ The user confirmed the fix. Only two things remain:
|
|
|
174
203
|
\`#region agent log\` wrapper, then call list_debug_probes and confirm the
|
|
175
204
|
ledger is empty. Keep the proven fix; remove nothing else.
|
|
176
205
|
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
|
|
206
|
+
Do not add probes, form new hypotheses, or ask for another reproduction, and do
|
|
207
|
+
not call ${HANDOFF_TOOL}: cleanup ends when the ledger is empty and you have
|
|
208
|
+
summarized.`;
|
|
178
209
|
|
|
179
210
|
/** Sent back into a cleanup turn that ended with probes still in the code. */
|
|
180
211
|
export const CLEANUP_NUDGE =
|