session lock and workspace processing refinements

This commit is contained in:
Rob Colbert 2026-05-02 11:21:41 -04:00
parent 4075a63aea
commit b84e06fac8
4 changed files with 36 additions and 21 deletions

View File

@ -123,8 +123,6 @@ export class CodeSession extends SocketSession {
droneSession.socket.emit( droneSession.socket.emit(
"processWorkOrder", "processWorkOrder",
this.selectedDrone, this.selectedDrone,
this.project,
this.chatSession,
turn, turn,
(success: boolean, message?: string) => { (success: boolean, message?: string) => {
if (success) { if (success) {

View File

@ -150,8 +150,6 @@ describe("CodeSession", () => {
expect(mockDroneSession.socket.emit).toHaveBeenCalledWith( expect(mockDroneSession.socket.emit).toHaveBeenCalledWith(
"processWorkOrder", "processWorkOrder",
mockDrone, mockDrone,
mockProject,
mockChatSession,
mockTurn, mockTurn,
expect.any(Function), expect.any(Function),
); );

View File

@ -33,6 +33,11 @@ interface UserCredentials {
password: string; password: string;
} }
interface ISessionLock {
project: IProject;
session: IChatSession;
}
type ClientSocket = Socket<ServerToClientEvents, ClientToServerEvents>; type ClientSocket = Socket<ServerToClientEvents, ClientToServerEvents>;
class GadgetDrone extends GadgetProcess { class GadgetDrone extends GadgetProcess {
@ -40,7 +45,7 @@ class GadgetDrone extends GadgetProcess {
private user: IUser | undefined; private user: IUser | undefined;
private workspaceMode: WorkspaceMode = WorkspaceMode.Syncing; private workspaceMode: WorkspaceMode = WorkspaceMode.Syncing;
private chatSession: IChatSession | undefined; private sessionLock: ISessionLock | undefined;
private socket: ClientSocket | undefined; private socket: ClientSocket | undefined;
private isShuttingDown: boolean = false; private isShuttingDown: boolean = false;
@ -245,16 +250,22 @@ class GadgetDrone extends GadgetProcess {
* Check if the chat session lock is already held. * Check if the chat session lock is already held.
*/ */
if (this.chatSession) { if (this.sessionLock) {
if (chatSession._id !== this.chatSession._id) { if (chatSession._id !== this.sessionLock.session._id) {
this.log.warn("rejecting session lock request", { this.log.warn("rejecting session lock request", {
chatSession: { sessionLock: {
_id: this.chatSession._id, project: {
name: this.chatSession.name, _id: this.sessionLock.project._id,
name: this.sessionLock.project.name,
},
session: {
_id: this.sessionLock.session._id,
name: this.sessionLock.session.name,
},
}, },
workspaceMode: this.workspaceMode, workspaceMode: this.workspaceMode,
}); });
return cb(false, this.chatSession._id); return cb(false, this.sessionLock.session._id);
} }
// fall through to grant this lock request // fall through to grant this lock request
this.log.info("chat session is re-connecting to session lock"); this.log.info("chat session is re-connecting to session lock");
@ -269,7 +280,10 @@ class GadgetDrone extends GadgetProcess {
project: { _id: project._id, slug: project.slug }, project: { _id: project._id, slug: project.slug },
chatSession: { _id: chatSession._id, name: chatSession.name }, chatSession: { _id: chatSession._id, name: chatSession.name },
}); });
this.chatSession = chatSession; this.sessionLock = {
project,
session: chatSession,
};
this.workspaceMode = WorkspaceMode.Idle; this.workspaceMode = WorkspaceMode.Idle;
cb(true, chatSession._id); cb(true, chatSession._id);
@ -282,10 +296,10 @@ class GadgetDrone extends GadgetProcess {
mode: WorkspaceMode, mode: WorkspaceMode,
cb: RequestWorkspaceModeCallback, cb: RequestWorkspaceModeCallback,
) { ) {
if (!this.chatSession) { if (!this.sessionLock) {
return cb(false, this.workspaceMode); return cb(false, this.workspaceMode);
} }
if (chatSession._id !== this.chatSession._id) { if (chatSession._id !== this.sessionLock.session._id) {
this.log.warn("rejecting workspace mode request", { this.log.warn("rejecting workspace mode request", {
chatSession: { _id: chatSession._id, name: chatSession.name }, chatSession: { _id: chatSession._id, name: chatSession.name },
}); });
@ -306,17 +320,24 @@ class GadgetDrone extends GadgetProcess {
async onProcessWorkOrder( async onProcessWorkOrder(
registration: IDroneRegistration, registration: IDroneRegistration,
project: IProject,
chatSession: IChatSession,
turn: IChatTurn, turn: IChatTurn,
cb: ProcessWorkOrderCallback, cb: ProcessWorkOrderCallback,
) { ) {
if (!this.chatSession) { const project = turn.project as IProject;
const session = turn.session as IChatSession;
if (!this.sessionLock) {
return cb(false, "this drone is not locked to a chat session"); return cb(false, "this drone is not locked to a chat session");
} }
if (this.chatSession._id !== chatSession._id) { if (this.sessionLock.session._id !== session._id) {
return cb(false, "this drone is not locked to your chat session"); return cb(false, "this drone is not locked to your chat session");
} }
if (this.sessionLock.project._id !== project._id) {
return cb(
false,
`this drone is locked to a different project: ${this.sessionLock.project.name}`,
);
}
if (this.workspaceMode !== WorkspaceMode.Agent) { if (this.workspaceMode !== WorkspaceMode.Agent) {
return cb(false, "this drone's workspace is not in Agent mode"); return cb(false, "this drone's workspace is not in Agent mode");
} }
@ -329,7 +350,7 @@ class GadgetDrone extends GadgetProcess {
this.log.info("processWorkOrder received", { this.log.info("processWorkOrder received", {
registration: { _id: registration._id }, registration: { _id: registration._id },
project: { _id: project._id, name: project.name }, project: { _id: project._id, name: project.name },
chatSession: { _id: chatSession._id, name: chatSession.name }, session: { _id: session._id, name: session.name },
turn: { _id: turn._id, mode: turn.mode, userPrompt: turn.prompts.user }, turn: { _id: turn._id, mode: turn.mode, userPrompt: turn.prompts.user },
}); });

View File

@ -13,8 +13,6 @@ export type ProcessWorkOrderCallback = (
) => void; ) => void;
export type ProcessWorkOrderMessage = ( export type ProcessWorkOrderMessage = (
registration: IDroneRegistration, registration: IDroneRegistration,
project: IProject,
chatSession: IChatSession,
turn: IChatTurn, turn: IChatTurn,
cb: ProcessWorkOrderCallback, cb: ProcessWorkOrderCallback,
) => void; ) => void;