-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Add an API for resuming tasks by ID #7122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # IPC (Inter-Process Communication) | ||
|
|
||
| This package provides IPC functionality for Roo Code, allowing external applications to communicate with the extension through a socket-based interface. | ||
|
|
||
| ## Available Commands | ||
|
|
||
| The IPC interface supports the following task commands: | ||
|
|
||
| ### StartNewTask | ||
|
|
||
| Starts a new task with optional configuration and initial message. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `configuration`: RooCode settings object | ||
| - `text`: Initial task message (string) | ||
| - `images`: Array of image data URIs (optional) | ||
| - `newTab`: Whether to open in a new tab (boolean, optional) | ||
|
|
||
| ### CancelTask | ||
|
|
||
| Cancels a running task. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `data`: Task ID to cancel (string) | ||
|
|
||
| ### CloseTask | ||
|
|
||
| Closes a task and performs cleanup. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `data`: Task ID to close (string) | ||
|
|
||
| ### ResumeTask | ||
|
|
||
| Resumes a task from history. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `data`: Task ID to resume (string) | ||
|
|
||
| **Error Handling:** | ||
|
|
||
| - If the task ID is not found in history, the command will fail gracefully without crashing the IPC server | ||
| - Errors are logged for debugging purposes but do not propagate to the client | ||
|
|
||
| ## Usage Example | ||
|
|
||
| ```typescript | ||
| import { IpcClient } from "@roo-code/ipc" | ||
|
|
||
| const client = new IpcClient("/path/to/socket") | ||
|
|
||
| // Resume a task | ||
| client.sendCommand({ | ||
| commandName: "ResumeTask", | ||
| data: "task-123", | ||
| }) | ||
|
|
||
| // Start a new task | ||
| client.sendCommand({ | ||
| commandName: "StartNewTask", | ||
| data: { | ||
| configuration: { | ||
| /* RooCode settings */ | ||
| }, | ||
| text: "Hello, world!", | ||
| images: [], | ||
| newTab: false, | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| ## Events | ||
|
|
||
| The IPC interface also emits task events that clients can listen to: | ||
|
|
||
| - `TaskStarted`: When a task begins | ||
| - `TaskCompleted`: When a task finishes | ||
| - `TaskAborted`: When a task is cancelled | ||
| - `Message`: When a task sends a message | ||
|
|
||
| ## Socket Path | ||
|
|
||
| The socket path is typically located in the system's temporary directory and follows the pattern: | ||
|
|
||
| - Unix/Linux/macOS: `/tmp/roo-code-{id}.sock` | ||
| - Windows: `\\.\pipe\roo-code-{id}` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import { describe, it, expect } from "vitest" | ||
| import { TaskCommandName, taskCommandSchema } from "../ipc.js" | ||
|
|
||
| describe("IPC Types", () => { | ||
| describe("TaskCommandName", () => { | ||
| it("should include ResumeTask command", () => { | ||
| expect(TaskCommandName.ResumeTask).toBe("ResumeTask") | ||
| }) | ||
|
|
||
| it("should have all expected task commands", () => { | ||
| const expectedCommands = ["StartNewTask", "CancelTask", "CloseTask", "ResumeTask"] | ||
| const actualCommands = Object.values(TaskCommandName) | ||
|
|
||
| expectedCommands.forEach((command) => { | ||
| expect(actualCommands).toContain(command) | ||
| }) | ||
| }) | ||
|
|
||
| describe("Error Handling", () => { | ||
| it("should handle ResumeTask command gracefully when task not found", () => { | ||
| // This test verifies the schema validation - the actual error handling | ||
| // for invalid task IDs is tested at the API level, not the schema level | ||
| const resumeTaskCommand = { | ||
| commandName: TaskCommandName.ResumeTask, | ||
| data: "non-existent-task-id", | ||
| } | ||
|
|
||
| const result = taskCommandSchema.safeParse(resumeTaskCommand) | ||
| expect(result.success).toBe(true) | ||
|
|
||
| if (result.success) { | ||
| expect(result.data.commandName).toBe("ResumeTask") | ||
| expect(result.data.data).toBe("non-existent-task-id") | ||
| } | ||
| }) | ||
| }) | ||
| }) | ||
|
|
||
| describe("taskCommandSchema", () => { | ||
| it("should validate ResumeTask command with taskId", () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good test coverage for the schema validation! These tests ensure the ResumeTask command is properly validated. Could we also consider adding an integration test that verifies the actual task resumption flow works end-to-end? |
||
| const resumeTaskCommand = { | ||
| commandName: TaskCommandName.ResumeTask, | ||
| data: "task-123", | ||
| } | ||
|
|
||
| const result = taskCommandSchema.safeParse(resumeTaskCommand) | ||
| expect(result.success).toBe(true) | ||
|
|
||
| if (result.success) { | ||
| expect(result.data.commandName).toBe("ResumeTask") | ||
| expect(result.data.data).toBe("task-123") | ||
| } | ||
| }) | ||
|
|
||
| it("should reject ResumeTask command with invalid data", () => { | ||
| const invalidCommand = { | ||
| commandName: TaskCommandName.ResumeTask, | ||
| data: 123, // Should be string | ||
| } | ||
|
|
||
| const result = taskCommandSchema.safeParse(invalidCommand) | ||
| expect(result.success).toBe(false) | ||
| }) | ||
|
|
||
| it("should reject ResumeTask command without data", () => { | ||
| const invalidCommand = { | ||
| commandName: TaskCommandName.ResumeTask, | ||
| // Missing data field | ||
| } | ||
|
|
||
| const result = taskCommandSchema.safeParse(invalidCommand) | ||
| expect(result.success).toBe(false) | ||
| }) | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,7 @@ export enum TaskCommandName { | |
| StartNewTask = "StartNewTask", | ||
| CancelTask = "CancelTask", | ||
| CloseTask = "CloseTask", | ||
| ResumeTask = "ResumeTask", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clean addition to the enum and schema! The ResumeTask command follows the same pattern as the other task commands, maintaining consistency in the API design. |
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -68,6 +69,10 @@ export const taskCommandSchema = z.discriminatedUnion("commandName", [ | |
| commandName: z.literal(TaskCommandName.CloseTask), | ||
| data: z.string(), | ||
| }), | ||
| z.object({ | ||
| commandName: z.literal(TaskCommandName.ResumeTask), | ||
| data: z.string(), | ||
| }), | ||
| ]) | ||
|
|
||
| export type TaskCommand = z.infer<typeof taskCommandSchema> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent documentation! The ResumeTask command is clearly documented with its parameters and usage example. This makes it easy for external applications to understand how to use this new functionality.