• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

waldiez / jupyter / 18614827256

18 Oct 2025 11:07AM UTC coverage: 88.709% (-1.6%) from 90.289%
18614827256

push

github

lazToum
bump to 0.6.1

346 of 440 branches covered (78.64%)

Branch coverage included in aggregate %.

1406 of 1535 relevant lines covered (91.6%)

9.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.16
/src/editor/executionManager.ts
1
/**
2
 * SPDX-License-Identifier: Apache-2.0
3
 * Copyright 2024 - 2025 Waldiez & contributors
4
 */
5
import { WALDIEZ_STRINGS } from "../constants";
10✔
6
import { WaldiezLogger } from "../logger";
10✔
7
import { getWaldiezActualPath } from "../rest";
10✔
8
import { WaldiezStandardRunner, WaldiezStepRunner } from "../runner";
10✔
9
import { WaldiezKernelManager } from "./kernelManager";
10✔
10
import type { IEditorState, IExecutionContext } from "./types";
11
import type { ISessionContext } from "@jupyterlab/apputils";
12
import type { IInputRequestMsg } from "@jupyterlab/services/lib/kernel/messages";
13
import { Signal } from "@lumino/signaling";
10✔
14

15
import type {
16
    WaldiezBreakpoint,
17
    WaldiezChatConfig,
18
    WaldiezChatHandlers,
19
    WaldiezChatMessage,
20
    WaldiezChatUserInput,
21
    WaldiezDebugInputResponse,
22
    WaldiezStepByStep,
23
    WaldiezStepHandlers,
24
} from "@waldiez/react";
25

26
/**
27
 * Manages execution state and runner coordination.
28
 */
29
export class WaldiezExecutionManager {
10✔
30
    private _standardRunner: WaldiezStandardRunner;
59✔
31
    private _stepRunner: WaldiezStepRunner;
59✔
32
    private _state: IEditorState;
59✔
33
    private readonly _logger: WaldiezLogger;
59✔
34
    private _signal: Signal<
59✔
35
        any,
36
        { chat: WaldiezChatConfig | undefined; stepByStep: WaldiezStepByStep | undefined }
37
    >;
38

39
    private _sessionContext: ISessionContext | null = null;
59✔
40
    private _kernelManager: WaldiezKernelManager | null = null;
59✔
41

42
    constructor(
43
        logger: WaldiezLogger,
44
        baseUrl: string,
45
        signal: Signal<
46
            any,
47
            { chat: WaldiezChatConfig | undefined; stepByStep: WaldiezStepByStep | undefined }
48
        >,
49
    ) {
50
        this._logger = logger;
59✔
51
        this._signal = signal;
59✔
52

53
        // Initialize runners
54
        this._standardRunner = new WaldiezStandardRunner({
59✔
55
            logger: this._logger,
56
            baseUrl,
57
            onStdin: this._onChatStdin.bind(this),
58
            onUpdate: this._onChatUpdate.bind(this),
59
            onEnd: this._onEnd.bind(this),
60
        });
61

62
        this._stepRunner = new WaldiezStepRunner({
59✔
63
            logger: this._logger,
64
            baseUrl,
65
            onStdin: this._onStepStdin.bind(this),
66
            onUpdate: this._onStepUpdate.bind(this),
67
            onEnd: this._onEnd.bind(this),
68
        });
69

70
        const chatHandlers: WaldiezChatHandlers = {
59✔
71
            onUserInput: this._createUserInputHandler(),
72
            onInterrupt: this._createInterruptHandler(),
73
            onClose: this._createCloseHandler(),
74
        };
75

76
        const stepByStepHandlers: WaldiezStepHandlers = {
59✔
77
            sendControl: this._createSendControlHandler(),
78
            close: this.closeStepByStepSession.bind(this),
79
            respond: this._createStepByStepRespondHandler(),
80
        };
81

82
        this._state = {
59✔
83
            chat: {
84
                show: false,
85
                active: false,
86
                messages: [] as WaldiezChatMessage[],
87
                timeline: undefined,
88
                userParticipants: [],
89
                handlers: chatHandlers,
90
            },
91
            stepByStep: {
92
                show: false,
93
                active: false,
94
                stepMode: true,
95
                autoContinue: false,
96
                breakpoints: [],
97
                eventHistory: [],
98
                currentEvent: undefined,
99
                timeline: undefined,
100
                participants: [],
101
                help: undefined,
102
                lastError: undefined,
103
                pendingControlInput: null,
104
                activeRequest: null,
105
                handlers: stepByStepHandlers,
106
            },
107
            stdinRequest: null,
108
        };
109
    }
110

111
    _resetStepByStepState() {
112
        this._state.stepByStep = {
1✔
113
            ...this._state.stepByStep,
114
            active: false,
115
            stepMode: true,
116
            autoContinue: false,
117
            breakpoints: [],
118
            eventHistory: [],
119
            currentEvent: undefined,
120
            timeline: undefined,
121
            participants: [],
122
            help: undefined,
123
            lastError: undefined,
124
            pendingControlInput: null,
125
            activeRequest: null,
126
        };
127
    }
128

129
    /**
130
     * Set the dependencies that handlers need access to.
131
     * This should be called after the manager is created.
132
     */
133
    setDependencies(sessionContext: ISessionContext, kernelManager: WaldiezKernelManager): void {
134
        this._sessionContext = sessionContext;
23✔
135
        this._kernelManager = kernelManager;
23✔
136
    }
137

138
    // Handler factory methods that capture dependencies
139
    private _createUserInputHandler() {
140
        return (userInput: WaldiezChatUserInput) => {
61✔
141
            if (!this._sessionContext) {
2!
142
                console.error("SessionContext not available for user input");
2✔
143
                return;
2✔
144
            }
145
            this.handleUserInput(userInput, this._sessionContext);
×
146
        };
147
    }
148

149
    private _createInterruptHandler() {
150
        return () => {
61✔
151
            if (!this._kernelManager) {
2!
152
                console.error("KernelManager not available for interrupt");
2✔
153
                return;
2✔
154
            }
155
            this.handleInterrupt(this._kernelManager);
×
156
        };
157
    }
158

159
    private _createCloseHandler() {
160
        return () => {
59✔
161
            if (!this._kernelManager) {
×
162
                console.error("KernelManager not available for close");
×
163
                return;
×
164
            }
165
            this.handleClose();
×
166
        };
167
    }
168

169
    private _createSendControlHandler() {
170
        return (input: Pick<WaldiezDebugInputResponse, "data" | "request_id">) => {
61✔
171
            if (!this._sessionContext) {
2!
172
                console.error("SessionContext not available for send control");
2✔
173
                return;
2✔
174
            }
175
            this.sendControl(input, this._sessionContext);
×
176
        };
177
    }
178

179
    private _createStepByStepRespondHandler() {
180
        return (response: WaldiezChatUserInput) => {
61✔
181
            if (!this._sessionContext) {
2!
182
                console.error("SessionContext not available for step response");
2✔
183
                return;
2✔
184
            }
185
            this.stepByStepRespond(response, this._sessionContext);
×
186
        };
187
    }
188

189
    // Standard execution methods
190
    async executeStandard(context: IExecutionContext): Promise<void> {
191
        if (!context.kernel) {
3✔
192
            throw new Error(WALDIEZ_STRINGS.NO_KERNEL);
1✔
193
        }
194

195
        this._signal.emit({ chat: undefined, stepByStep: undefined });
2✔
196

197
        try {
2✔
198
            const actualPath = await getWaldiezActualPath(context.filePath);
2✔
199
            this._standardRunner.run(context.kernel, actualPath);
1✔
200
        } catch (err) {
201
            this._logger.log({
1✔
202
                data: String(err),
203
                level: "error",
204
                type: "text",
205
            });
206
            throw err;
1✔
207
        }
208
    }
209

210
    // Step-by-step execution methods
211
    async executeStepByStep(
212
        context: IExecutionContext,
213
        breakpoints?: (string | WaldiezBreakpoint)[],
214
    ): Promise<void> {
215
        if (!context.kernel) {
2✔
216
            throw new Error(WALDIEZ_STRINGS.NO_KERNEL);
1✔
217
        }
218

219
        this._signal.emit({ chat: undefined, stepByStep: undefined });
1✔
220

221
        try {
1✔
222
            const actualPath = await getWaldiezActualPath(context.filePath);
1✔
223
            this._stepRunner.start(context.kernel, actualPath, breakpoints);
1✔
224
        } catch (err) {
225
            this._logger.log({
×
226
                data: (err as Error).message || String(err),
×
227
                level: "error",
228
                type: "text",
229
            });
230
            throw err;
×
231
        }
232
    }
233

234
    // Input handling methods
235
    handleUserInput(userInput: WaldiezChatUserInput, sessionContext: ISessionContext): void {
236
        if (this._state.stdinRequest) {
2✔
237
            this._logger.log({
1✔
238
                data: JSON.stringify(userInput),
239
                level: "info",
240
                type: "text",
241
            });
242
            sessionContext.session?.kernel?.sendInputReply(
1✔
243
                { value: JSON.stringify(userInput), status: "ok" },
244
                this._state.stdinRequest.parent_header as any,
245
            );
246
            this._state.stdinRequest = null;
1✔
247
        }
248
    }
249

250
    handleInterrupt(kernelManager: WaldiezKernelManager): void {
251
        this._state.stdinRequest = null;
1✔
252
        this._standardRunner.reset();
1✔
253
        this._standardRunner.setTimelineData(undefined);
1✔
254
        this._signal.emit({
1✔
255
            chat: {
256
                show: false,
257
                active: false,
258
                messages: this._standardRunner.getPreviousMessages(),
259
                timeline: undefined,
260
                userParticipants: this._standardRunner.getUserParticipants(),
261
                activeRequest: undefined,
262
            },
263
            stepByStep: undefined,
264
        });
265
        // noinspection JSIgnoredPromiseFromCall
266
        kernelManager.restart();
1✔
267
    }
268

269
    handleClose(): void {
270
        this._state.stdinRequest = null;
1✔
271
        this._standardRunner.reset(true);
1✔
272
        this._signal.emit({
1✔
273
            chat: undefined,
274
            stepByStep: undefined,
275
        });
276
        if (this._kernelManager) {
1!
277
            // noinspection JSIgnoredPromiseFromCall
278
            this._kernelManager.restart();
×
279
        }
280
    }
281

282
    sendControl(
283
        input: Pick<WaldiezDebugInputResponse, "data" | "request_id">,
284
        sessionContext: ISessionContext,
285
    ): void {
286
        if (this._state.stdinRequest) {
2✔
287
            input.request_id = this._stepRunner.requestId || input.request_id || "<unknown>";
1!
288
            sessionContext.session?.kernel?.sendInputReply(
1✔
289
                { value: JSON.stringify({ ...input, type: "debug_input_response" }), status: "ok" },
290
                this._state.stdinRequest.parent_header as any,
291
            );
292
        } else {
293
            console.error("StepByStep response received without stdin request");
1✔
294
        }
295
        this._state.stdinRequest = null;
2✔
296
        const isQuit = input.data === "q";
2✔
297
        if (isQuit) {
2!
298
            this.closeStepByStepSession();
×
299
        } else {
300
            this._stepRunner.responded();
2✔
301
        }
302
    }
303

304
    stepByStepRespond(response: WaldiezChatUserInput, sessionContext: ISessionContext): void {
305
        if (this._state.stdinRequest) {
1!
306
            sessionContext.session?.kernel?.sendInputReply(
1✔
307
                { value: JSON.stringify(response), status: "ok" },
308
                this._state.stdinRequest.parent_header as any,
309
            );
310
        }
311
        this._state.stdinRequest = null;
1✔
312
        this._stepRunner.responded();
1✔
313
    }
314

315
    closeStepByStepSession(): void {
316
        this._resetStepByStepState();
1✔
317
        this._signal.emit({ chat: undefined, stepByStep: undefined });
1✔
318
        this._stepRunner.reset();
1✔
319

320
        if (this._kernelManager) {
1!
321
            // noinspection JSIgnoredPromiseFromCall
322
            this._kernelManager.restart();
×
323
        }
324
    }
325

326
    // Event handlers for runners
327
    private _onChatStdin(msg: IInputRequestMsg): void {
328
        let prompt = msg.content.prompt;
2✔
329
        if (prompt === ">" || prompt === "> ") {
2✔
330
            prompt = WALDIEZ_STRINGS.ON_EMPTY_PROMPT;
1✔
331
        }
332
        this._logger.log({
2✔
333
            data: prompt,
334
            level: "warning",
335
            type: "text",
336
        });
337
        this._state.stdinRequest = msg;
2✔
338
        this._askForInput();
2✔
339
    }
340

341
    private _onStepStdin(msg: IInputRequestMsg): void {
342
        let prompt = msg.content.prompt;
1✔
343
        if (prompt === ">" || prompt === "> ") {
1!
344
            prompt = WALDIEZ_STRINGS.ON_EMPTY_PROMPT;
×
345
        }
346
        this._logger.log({
1✔
347
            data: prompt,
348
            level: "warning",
349
            type: "text",
350
        });
351
        this._state.stdinRequest = msg;
1✔
352
    }
353

354
    private _askForInput(): void {
355
        const messages = this._standardRunner.getPreviousMessages();
2✔
356
        let request_id: string;
357
        if (typeof this._state.stdinRequest?.metadata.request_id === "string") {
2✔
358
            request_id = this._state.stdinRequest.metadata.request_id;
1✔
359
        } else {
360
            request_id = this._standardRunner.requestId ?? this._getRequestIdFromPreviousMessages(messages);
1!
361
        }
362

363
        const chat: WaldiezChatConfig = {
2✔
364
            ...this._state.chat,
365
            show: true,
366
            active: true,
367
            messages,
368
            userParticipants: this._standardRunner.getUserParticipants(),
369
            activeRequest: {
370
                request_id,
371
                prompt: this._state.stdinRequest?.content.prompt ?? "> ",
2!
372
                password: this._state.stdinRequest?.content.password ?? false,
2!
373
            },
374
        };
375
        this._signal.emit({ chat, stepByStep: undefined });
2✔
376
    }
377

378
    private _onEnd(): void {
379
        this._signal.emit({
1✔
380
            chat: {
381
                ...this._state.chat,
382
                messages: this._standardRunner.getPreviousMessages(),
383
                timeline: this._standardRunner.getTimelineData(),
384
                userParticipants: this._standardRunner.getUserParticipants(),
385
                activeRequest: undefined,
386
                handlers: undefined,
387
            },
388
            stepByStep: undefined,
389
        });
390
    }
391

392
    private _onChatUpdate(updateData: Partial<WaldiezChatConfig>): void {
393
        const { handlers, ...restUpdateData } = updateData;
1✔
394

395
        const chatConfig = {
1✔
396
            ...this._state.chat,
397
            ...restUpdateData,
398
            handlers: {
399
                ...this._state.chat.handlers,
400
                ...(handlers || {}),
2✔
401
            },
402
        };
403
        this._state.chat = chatConfig;
1✔
404
        this._signal.emit({
1✔
405
            chat: chatConfig,
406
            stepByStep: undefined,
407
        });
408
    }
409

410
    private _onStepUpdate(updateData: Partial<WaldiezStepByStep>): void {
411
        const { show, active, ...restStepUpdateData } = updateData;
3✔
412
        this._state.stepByStep = {
3✔
413
            ...this._state.stepByStep,
414
            ...restStepUpdateData,
415
            show: typeof show === "boolean" ? show : this._state.stepByStep.show,
3!
416
            active: typeof active === "boolean" ? active : this._state.stepByStep.active,
3✔
417
        };
418
        this._signal.emit({
3✔
419
            chat: undefined,
420
            stepByStep: this._state.stepByStep,
421
        });
422
    }
423

424
    private _getRequestIdFromPreviousMessages(previousMessages: WaldiezChatMessage[]): string {
425
        const inputRequestMessage = previousMessages.find(msg => msg.type === "input_request");
11✔
426
        if (inputRequestMessage) {
8✔
427
            return inputRequestMessage.request_id ?? "<unknown>";
6✔
428
        }
429
        return "<unknown>";
2✔
430
    }
431

432
    dispose(): void {
433
        this._standardRunner.reset(true);
80✔
434
        this._stepRunner.reset();
80✔
435
    }
436
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc