Skip to content

Commit 06be9d6

Browse files
authored
Merge pull request #171 from SentienceAPI/tighten2
updated debugger doc with reacordAction, autoStop, stepId 0-based
2 parents cf248e9 + 23035cd commit 06be9d6

4 files changed

Lines changed: 83 additions & 8 deletions

File tree

src/agent-runtime.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,8 @@ export class AgentRuntime {
355355
/** Current step identifier */
356356
stepId: string | null = null;
357357
/** Current step index (0-based) */
358-
stepIndex: number = 0;
358+
// 0-based step indexing (first auto-generated stepId is "step-0")
359+
stepIndex: number = -1;
359360
/** Most recent snapshot (for assertion context) */
360361
lastSnapshot: Snapshot | null = null;
361362
private stepPreSnapshot: Snapshot | null = null;

src/debugger.ts

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,53 @@
11
import { Page } from 'playwright';
22

3-
import { AgentRuntime, AttachOptions } from './agent-runtime';
3+
import { AgentRuntime, AssertionHandle, AttachOptions } from './agent-runtime';
44
import { Predicate } from './verification';
55
import { Tracer } from './tracing/tracer';
66

7+
class DebuggerAssertionHandle extends AssertionHandle {
8+
private dbg: SentienceDebugger;
9+
private autoClose: boolean;
10+
private openedStepId: string | null;
11+
12+
constructor(
13+
dbg: SentienceDebugger,
14+
predicate: Predicate,
15+
label: string,
16+
required: boolean,
17+
autoClose: boolean,
18+
openedStepId: string | null
19+
) {
20+
super(dbg.runtime, predicate, label, required);
21+
this.dbg = dbg;
22+
this.autoClose = autoClose;
23+
this.openedStepId = openedStepId;
24+
}
25+
26+
override once(): boolean {
27+
const ok = super.once();
28+
if (this.autoClose && this.dbg.isAutoStepOpenFor(this.openedStepId)) {
29+
void this.dbg.endStep();
30+
}
31+
return ok;
32+
}
33+
34+
override async eventually(
35+
options: Parameters<AssertionHandle['eventually']>[0] = {}
36+
): Promise<boolean> {
37+
const ok = await super.eventually(options);
38+
if (this.autoClose && this.dbg.isAutoStepOpenFor(this.openedStepId)) {
39+
await this.dbg.endStep();
40+
}
41+
return ok;
42+
}
43+
}
44+
745
export class SentienceDebugger {
846
readonly runtime: AgentRuntime;
947
private stepOpen: boolean = false;
1048
private autoStep: boolean = true;
49+
private autoOpenedStep: boolean = false;
50+
private autoOpenedStepId: string | null = null;
1151

1252
constructor(runtime: AgentRuntime, options?: { autoStep?: boolean }) {
1353
this.runtime = runtime;
@@ -19,13 +59,31 @@ export class SentienceDebugger {
1959
return new SentienceDebugger(runtime);
2060
}
2161

62+
isAutoStepOpenFor(stepId: string | null): boolean {
63+
return Boolean(
64+
this.stepOpen &&
65+
this.autoOpenedStep &&
66+
this.autoOpenedStepId &&
67+
stepId &&
68+
this.autoOpenedStepId === stepId
69+
);
70+
}
71+
2272
beginStep(goal: string, stepIndex?: number): string {
73+
// If we previously auto-opened a verification step, close it before starting a real step.
74+
if (this.stepOpen && this.autoOpenedStep) {
75+
void this.endStep();
76+
this.autoOpenedStep = false;
77+
this.autoOpenedStepId = null;
78+
}
2379
this.stepOpen = true;
2480
return this.runtime.beginStep(goal, stepIndex);
2581
}
2682

2783
async endStep(opts: Parameters<AgentRuntime['emitStepEnd']>[0] = {}): Promise<any> {
2884
this.stepOpen = false;
85+
this.autoOpenedStep = false;
86+
this.autoOpenedStepId = null;
2987
// emitStepEnd is synchronous; wrap to satisfy async/await lint rules.
3088
return await Promise.resolve(this.runtime.emitStepEnd(opts));
3189
}
@@ -43,7 +101,13 @@ export class SentienceDebugger {
43101
return this.runtime.snapshot(options);
44102
}
45103

104+
async recordAction(action: string, url?: string): Promise<void> {
105+
return await this.runtime.recordAction(action, url);
106+
}
107+
46108
check(predicate: Predicate, label: string, required: boolean = false) {
109+
let didAutoOpen = false;
110+
let openedStepId: string | null = null;
47111
if (!this.stepOpen) {
48112
if (!this.autoStep) {
49113
throw new Error(
@@ -53,7 +117,17 @@ export class SentienceDebugger {
53117
);
54118
}
55119
this.beginStep(`verify:${label}`);
120+
didAutoOpen = true;
121+
openedStepId = this.runtime.stepId;
122+
this.autoOpenedStep = true;
123+
this.autoOpenedStepId = openedStepId;
124+
}
125+
const base = this.runtime.check(predicate, label, required);
126+
if (!didAutoOpen) {
127+
return base;
56128
}
57-
return this.runtime.check(predicate, label, required);
129+
// Return an auto-closing handle for the common "casual" sidecar usage pattern.
130+
// We still call runtime.check(...) above to keep behavior consistent.
131+
return new DebuggerAssertionHandle(this, predicate, label, required, true, openedStepId);
58132
}
59133
}

tests/agent-runtime-assertions.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ describe('AgentRuntime.beginStep() stepId format', () => {
5757
const runtime = new AgentRuntime(browserLike as any, page as any, tracer);
5858

5959
const stepId1 = runtime.beginStep('Step 1');
60-
expect(stepId1).toBe('step-1');
61-
expect(runtime.stepIndex).toBe(1);
60+
expect(stepId1).toBe('step-0');
61+
expect(runtime.stepIndex).toBe(0);
6262

6363
const stepId2 = runtime.beginStep('Step 2');
64-
expect(stepId2).toBe('step-2');
65-
expect(runtime.stepIndex).toBe(2);
64+
expect(stepId2).toBe('step-1');
65+
expect(runtime.stepIndex).toBe(1);
6666
});
6767

6868
it('generates stepId matching explicit stepIndex', () => {

tests/debugger.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe('SentienceDebugger', () => {
6464

6565
expect(runtime.beginStep).toHaveBeenCalledWith('verify:has_cart', undefined);
6666
expect(runtime.check).toHaveBeenCalled();
67-
expect(handle).toBe('handle');
67+
expect(typeof (handle as any).once).toBe('function');
6868
});
6969

7070
it('can disable auto-step (strict mode)', () => {

0 commit comments

Comments
 (0)