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

Method terminateDescendantAgentTask

src/node/services/taskService.ts:3721–3790  ·  view source on GitHub ↗
(
    ancestorWorkspaceId: string,
    taskId: string
  )

Source from the content-addressed store, hash-verified

3719 }
3720
3721 async terminateDescendantAgentTask(
3722 ancestorWorkspaceId: string,
3723 taskId: string
3724 ): Promise<Result<TerminateAgentTaskResult, string>> {
3725 assert(
3726 ancestorWorkspaceId.length > 0,
3727 "terminateDescendantAgentTask: ancestorWorkspaceId must be non-empty"
3728 );
3729 assert(taskId.length > 0, "terminateDescendantAgentTask: taskId must be non-empty");
3730
3731 const terminatedTaskIds: string[] = [];
3732
3733 {
3734 await using _lock = await this.mutex.acquire();
3735
3736 const cfg = this.config.loadConfigOrDefault();
3737 const entry = findWorkspaceEntry(cfg, taskId);
3738 if (!entry?.workspace.parentWorkspaceId) {
3739 return Err("Task not found");
3740 }
3741
3742 const index = this.buildAgentTaskIndex(cfg);
3743 if (
3744 !this.isDescendantAgentTaskUsingParentById(index.parentById, ancestorWorkspaceId, taskId)
3745 ) {
3746 return Err("Task is not a descendant of this workspace");
3747 }
3748
3749 // Terminate the entire subtree to avoid orphaned descendant tasks.
3750 const descendants = this.listDescendantAgentTaskIdsFromIndex(index, taskId);
3751 const toTerminate = Array.from(new Set([taskId, ...descendants]));
3752
3753 // Delete leaves first to avoid leaving children with missing parents.
3754 const parentById = index.parentById;
3755 const depthById = new Map<string, number>();
3756 for (const id of toTerminate) {
3757 depthById.set(id, this.getTaskDepthFromParentById(parentById, id));
3758 }
3759 toTerminate.sort((a, b) => (depthById.get(b) ?? 0) - (depthById.get(a) ?? 0));
3760
3761 const terminationError = new Error("Task terminated");
3762
3763 for (const id of toTerminate) {
3764 // Best-effort: stop any active stream immediately to avoid further token usage.
3765 try {
3766 const stopResult = await this.aiService.stopStream(id, { abandonPartial: true });
3767 if (!stopResult.success) {
3768 log.debug("terminateDescendantAgentTask: stopStream failed", { taskId: id });
3769 }
3770 } catch (error: unknown) {
3771 log.debug("terminateDescendantAgentTask: stopStream threw", { taskId: id, error });
3772 }
3773
3774 this.completedReportsByTaskId.delete(id);
3775 this.rejectWaiters(id, terminationError);
3776
3777 const removeResult = await this.workspaceService.remove(id, true);
3778 if (!removeResult.success) {

Callers 2

createTaskTerminateToolFunction · 0.80

Calls 15

buildAgentTaskIndexMethod · 0.95
rejectWaitersMethod · 0.95
maybeStartQueuedTasksMethod · 0.95
findWorkspaceEntryFunction · 0.90
ErrFunction · 0.90
OkFunction · 0.90
loadConfigOrDefaultMethod · 0.80
setMethod · 0.80
debugMethod · 0.80

Tested by

no test coverage detected