Skip to content

Commit 8ceeb46

Browse files
committed
Merge codex/supervisor-target-memory
# Conflicts: # packages/web/src/features/supervisor/views/shared/supervisor-card.tsx
2 parents 6647a36 + f78d13d commit 8ceeb46

32 files changed

Lines changed: 2618 additions & 295 deletions

packages/core/src/domain/supervisor.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,52 @@ export type CycleStatus =
1919

2020
export type CycleTrigger = "turn_completed" | "manual" | "scheduled";
2121

22-
export type SupervisorStopReason = "objective_complete" | "max_supervision_count_reached";
22+
export type SupervisorStopReason =
23+
| "objective_complete"
24+
| "max_supervision_count_reached"
25+
| "supervisor_uncertain"
26+
| "needs_user_input";
27+
28+
export type SupervisorPlanStepStatus = "pending" | "in_progress" | "done";
29+
30+
export interface SupervisorPlanStep {
31+
id: string;
32+
title: string;
33+
status: SupervisorPlanStepStatus;
34+
}
35+
36+
export interface SupervisorTargetMemory {
37+
targetId: string;
38+
planGenerated: boolean;
39+
plan: SupervisorPlanStep[];
40+
activeStepId?: string;
41+
progressSummary?: string;
42+
lastGuidance?: string;
43+
stalledCount: number;
44+
updatedAt: number;
45+
}
46+
47+
export interface SupervisorCycleStepUpdate {
48+
id: string;
49+
status: SupervisorPlanStepStatus;
50+
}
51+
52+
export interface SupervisorCycleTargetRecord {
53+
cycleId: string;
54+
targetId: string;
55+
startedAt: number;
56+
completedAt: number;
57+
result: "continue" | "stop" | "error";
58+
stopReason?: "objective_complete" | "supervisor_uncertain" | "needs_user_input";
59+
reason?: string;
60+
guidance?: string;
61+
progressSummary?: string;
62+
activeStepId?: string;
63+
stepUpdates?: SupervisorCycleStepUpdate[];
64+
injected?: boolean;
65+
attemptCount?: number;
66+
errorReason?: string;
67+
}
2368

2469
export type SupervisorCycleAttemptStatus = "evaluating" | "completed" | "failed" | "cancelled";
2570

@@ -65,6 +110,7 @@ export interface Supervisor {
65110
id: string;
66111
sessionId: string;
67112
workspaceId: string;
113+
targetId: string;
68114
state: SupervisorState;
69115
objective: string;
70116
evaluatorProviderId: string;
@@ -73,6 +119,8 @@ export interface Supervisor {
73119
completedSupervisionCount: number;
74120
scheduledAt?: number;
75121
stopReason?: SupervisorStopReason;
122+
currentTargetMemory?: SupervisorTargetMemory;
123+
recentTargetCycles?: SupervisorCycleTargetRecord[];
76124
cycles: SupervisorCycle[];
77125
lastCycleAt?: number;
78126
lastEvaluatedTurnId?: string;

packages/server/src/__tests__/db.test.ts

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
CURRENT_SCHEMA_VERSION,
99
IncompatibleSchemaError,
1010
V1_SCHEMA_SQL,
11+
V2_SCHEMA_SQL,
1112
} from "../storage/schema-version.js";
1213

1314
describe("Database", () => {
@@ -98,7 +99,7 @@ describe("Database", () => {
9899
expect(tables.map((table) => table.name)).not.toContain("_migrations");
99100
});
100101

101-
it("should upgrade a known v1 supervisor schema to v2 when user_version is unset", () => {
102+
it("should upgrade a known v1 supervisor schema to v3 when user_version is unset", () => {
102103
const dbPath = join(tempDir, "v1.db");
103104
const rawDb = new DatabaseSync(dbPath);
104105
rawDb.exec("PRAGMA user_version = 0");
@@ -108,13 +109,14 @@ describe("Database", () => {
108109
db = openDatabase(dbPath);
109110

110111
const userVersion = db.prepare("PRAGMA user_version").get() as { user_version: number };
111-
expect(userVersion.user_version).toBe(2);
112+
expect(userVersion.user_version).toBe(CURRENT_SCHEMA_VERSION);
112113

113114
const supervisorColumns = db.prepare("PRAGMA table_info(supervisors)").all() as Array<{
114115
name: string;
115116
}>;
116117
expect(supervisorColumns.map((column) => column.name)).toEqual(
117118
expect.arrayContaining([
119+
"target_id",
118120
"evaluator_model",
119121
"max_supervision_count",
120122
"completed_supervision_count",
@@ -138,6 +140,79 @@ describe("Database", () => {
138140
expect(upgradedIndex?.name).toBe("idx_supervisor_cycle_attempts_cycle");
139141
});
140142

143+
it("should upgrade a known v2 supervisor schema to v3 and backfill target ids", () => {
144+
const dbPath = join(tempDir, "v2.db");
145+
const rawDb = new DatabaseSync(dbPath);
146+
rawDb.exec("PRAGMA user_version = 2");
147+
rawDb.exec(V2_SCHEMA_SQL);
148+
rawDb.exec(`
149+
INSERT INTO workspaces (id, path, target_runtime, opened_at, last_active_at, ui_state)
150+
VALUES ('ws-1', '/workspace', 'native', 1, 1, '{}');
151+
`);
152+
rawDb.exec(`
153+
INSERT INTO terminals (id, workspace_id, kind, cwd, argv, cols, rows, created_at)
154+
VALUES ('term-1', 'ws-1', 'agent', '/workspace', '[]', 120, 30, 1);
155+
`);
156+
rawDb.exec(`
157+
INSERT INTO sessions (
158+
id, workspace_id, terminal_id, provider_id, capability, state, started_at, last_active_at
159+
) VALUES ('sess-1', 'ws-1', 'term-1', 'codex', 'full', 'idle', 1, 1);
160+
`);
161+
rawDb.exec(`
162+
INSERT INTO supervisors (
163+
id,
164+
session_id,
165+
workspace_id,
166+
state,
167+
objective,
168+
evaluator_provider_id,
169+
evaluator_model,
170+
max_supervision_count,
171+
completed_supervision_count,
172+
scheduled_at,
173+
stop_reason,
174+
last_cycle_at,
175+
last_evaluated_turn_id,
176+
error_reason,
177+
created_at,
178+
updated_at
179+
) VALUES (
180+
'sup-legacy',
181+
'sess-1',
182+
'ws-1',
183+
'idle',
184+
'Legacy supervisor',
185+
'codex',
186+
NULL,
187+
0,
188+
0,
189+
NULL,
190+
NULL,
191+
NULL,
192+
NULL,
193+
NULL,
194+
1,
195+
1
196+
);
197+
`);
198+
rawDb.close();
199+
200+
db = openDatabase(dbPath);
201+
202+
const userVersion = db.prepare("PRAGMA user_version").get() as { user_version: number };
203+
expect(userVersion.user_version).toBe(CURRENT_SCHEMA_VERSION);
204+
205+
const supervisorColumns = db.prepare("PRAGMA table_info(supervisors)").all() as Array<{
206+
name: string;
207+
}>;
208+
expect(supervisorColumns.map((column) => column.name)).toContain("target_id");
209+
210+
const upgradedRow = db
211+
.prepare("SELECT target_id FROM supervisors WHERE id = ?")
212+
.get("sup-legacy") as { target_id: string };
213+
expect(upgradedRow.target_id).toBe("legacy_sup-legacy");
214+
});
215+
141216
it("should restamp user_version for an already-current schema when it is unset", () => {
142217
const dbPath = join(tempDir, "current-unstamped.db");
143218
db = openDatabase(dbPath);

packages/server/src/__tests__/supervisor-integration.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
33
import type { ServerConfig } from "../config.js";
44
import { createServer, type Server } from "../server.js";
55
import type { SupervisorEvaluationContext } from "../supervisor/context-builder.js";
6-
import type { SupervisorResult } from "../supervisor/evaluator.js";
6+
import type { SupervisorEvaluationResult } from "../supervisor/evaluator.js";
77
import type { SupervisorManager } from "../supervisor/manager.js";
88
import { type CommandContext, dispatch } from "../ws/dispatch.js";
99

@@ -21,7 +21,7 @@ type MutableSupervisorManager = SupervisorManager & {
2121
supervisor: Supervisor,
2222
context: SupervisorEvaluationContext,
2323
options?: { signal?: AbortSignal }
24-
) => Promise<SupervisorResult>;
24+
) => Promise<SupervisorEvaluationResult>;
2525
};
2626
logger: unknown;
2727
};
@@ -103,12 +103,20 @@ describe("Supervisor integration", () => {
103103
terminalExcerpt: "assistant: built the persistent supervisor repos",
104104
evidenceSource: "headless_snapshot",
105105
latestUserInput: "run the tests",
106+
targetMemory: {
107+
targetId: "tgt-1",
108+
planGenerated: false,
109+
plan: [],
110+
stalledCount: 0,
111+
updatedAt: 1,
112+
},
106113
}),
107114
};
108115
supervisorManager.evaluator = {
109116
evaluate: async () => ({
110-
message: "",
111-
objectiveComplete: false,
117+
status: "continue",
118+
reason: "Keep going",
119+
guidance: "",
112120
}),
113121
};
114122
});

0 commit comments

Comments
 (0)