MCPcopy
hub / github.com/coder/mux / terminateAllDescendantAgentTasks

Method terminateAllDescendantAgentTasks

src/node/services/taskService.ts:3826–3928  ·  view source on GitHub ↗

* Interrupt all descendant agent tasks for a workspace (leaf-first). * * Rationale: when a user hard-interrupts a parent workspace, descendants must * also stop so they cannot later auto-resume the interrupted parent. * * Keep interrupted task workspaces on disk so users can inspect o

(
    workspaceId: string,
    options?: { workflowRunId?: string }
  )

Source from the content-addressed store, hash-verified

3824 * compatibility with existing call sites.
3825 */
3826 async terminateAllDescendantAgentTasks(
3827 workspaceId: string,
3828 options?: { workflowRunId?: string }
3829 ): Promise<string[]> {
3830 assert(
3831 workspaceId.length > 0,
3832 "terminateAllDescendantAgentTasks: workspaceId must be non-empty"
3833 );
3834
3835 const interruptedTaskIds: string[] = [];
3836
3837 {
3838 await using _lock = await this.mutex.acquire();
3839
3840 const cfg = this.config.loadConfigOrDefault();
3841 const index = this.buildAgentTaskIndex(cfg);
3842 const descendants = this.listDescendantAgentTaskIdsFromIndex(index, workspaceId).filter(
3843 (taskId) =>
3844 options?.workflowRunId == null ||
3845 this.isWorkflowRunDescendant(index, taskId, options.workflowRunId)
3846 );
3847 if (descendants.length === 0) {
3848 return interruptedTaskIds;
3849 }
3850
3851 // Interrupt leaves first to avoid descendant/ancestor status races.
3852 const parentById = index.parentById;
3853 const depthById = new Map<string, number>();
3854 for (const id of descendants) {
3855 depthById.set(id, this.getTaskDepthFromParentById(parentById, id));
3856 }
3857 descendants.sort((a, b) => (depthById.get(b) ?? 0) - (depthById.get(a) ?? 0));
3858
3859 const interruptionError = new Error("Parent workspace interrupted");
3860
3861 for (const id of descendants) {
3862 // Best-effort: clear queue first. AgentSession stream-end cleanup auto-flushes
3863 // queued messages, so descendants must not keep pending input after a hard interrupt.
3864 try {
3865 const clearQueueResult = this.workspaceService.clearQueue(id);
3866 if (!clearQueueResult.success) {
3867 log.debug("terminateAllDescendantAgentTasks: clearQueue failed", {
3868 taskId: id,
3869 error: clearQueueResult.error,
3870 });
3871 }
3872 } catch (error: unknown) {
3873 log.debug("terminateAllDescendantAgentTasks: clearQueue threw", { taskId: id, error });
3874 }
3875
3876 // Best-effort: stop any active stream immediately to avoid further token usage
3877 // while preserving commit-worthy partial progress for inspection/resume.
3878 try {
3879 const stopResult = await this.aiService.stopStream(id, { abandonPartial: false });
3880 if (!stopResult.success) {
3881 log.debug("terminateAllDescendantAgentTasks: stopStream failed", { taskId: id });
3882 }
3883 } catch (error: unknown) {

Callers 1

Calls 15

buildAgentTaskIndexMethod · 0.95
editWorkspaceEntryMethod · 0.95
rejectWaitersMethod · 0.95
emitWorkspaceMetadataMethod · 0.95
maybeStartQueuedTasksMethod · 0.95
loadConfigOrDefaultMethod · 0.80
setMethod · 0.80
debugMethod · 0.80

Tested by

no test coverage detected