@@ -50,6 +50,10 @@ const (
5050 ToolNameWorkspaceEditFile = "coder_workspace_edit_file"
5151 ToolNameWorkspaceEditFiles = "coder_workspace_edit_files"
5252 ToolNameWorkspacePortForward = "coder_workspace_port_forward"
53+ ToolNameCreateTask = "coder_create_task"
54+ ToolNameDeleteTask = "coder_delete_task"
55+ ToolNameListTasks = "coder_list_tasks"
56+ ToolNameGetTaskStatus = "coder_get_task_status"
5357)
5458
5559func NewDeps (client * codersdk.Client , opts ... func (* Deps )) (Deps , error ) {
@@ -223,6 +227,10 @@ var All = []GenericTool{
223227 WorkspaceEditFile .Generic (),
224228 WorkspaceEditFiles .Generic (),
225229 WorkspacePortForward .Generic (),
230+ CreateTask .Generic (),
231+ DeleteTask .Generic (),
232+ ListTasks .Generic (),
233+ GetTaskStatus .Generic (),
226234}
227235
228236type ReportTaskArgs struct {
@@ -344,7 +352,7 @@ is provisioned correctly and the agent can connect to the control plane.
344352 Properties : map [string ]any {
345353 "user" : map [string ]any {
346354 "type" : "string" ,
347- "description" : "Username or ID of the user to create the workspace for. Use the `me` keyword to create a workspace for the authenticated user." ,
355+ "description" : userDescription ( " create a workspace" ) ,
348356 },
349357 "template_version_id" : map [string ]any {
350358 "type" : "string" ,
@@ -1393,8 +1401,6 @@ type WorkspaceLSResponse struct {
13931401 Contents []WorkspaceLSFile `json:"contents"`
13941402}
13951403
1396- const workspaceDescription = "The workspace name in the format [owner/]workspace[.agent]. If an owner is not specified, the authenticated user is used."
1397-
13981404var WorkspaceLS = Tool [WorkspaceLSArgs , WorkspaceLSResponse ]{
13991405 Tool : aisdk.Tool {
14001406 Name : ToolNameWorkspaceLS ,
@@ -1750,6 +1756,237 @@ var WorkspacePortForward = Tool[WorkspacePortForwardArgs, WorkspacePortForwardRe
17501756 },
17511757}
17521758
1759+ type CreateTaskArgs struct {
1760+ Input string `json:"input"`
1761+ TemplateVersionID string `json:"template_version_id"`
1762+ TemplateVersionPresetID string `json:"template_version_preset_id"`
1763+ User string `json:"user"`
1764+ }
1765+
1766+ var CreateTask = Tool [CreateTaskArgs , codersdk.Task ]{
1767+ Tool : aisdk.Tool {
1768+ Name : ToolNameCreateTask ,
1769+ Description : `Create a task.` ,
1770+ Schema : aisdk.Schema {
1771+ Properties : map [string ]any {
1772+ "input" : map [string ]any {
1773+ "type" : "string" ,
1774+ "description" : "Input/prompt for the task." ,
1775+ },
1776+ "template_version_id" : map [string ]any {
1777+ "type" : "string" ,
1778+ "description" : "ID of the template version to create the task from." ,
1779+ },
1780+ "template_version_preset_id" : map [string ]any {
1781+ "type" : "string" ,
1782+ "description" : "Optional ID of the template version preset to create the task from." ,
1783+ },
1784+ "user" : map [string ]any {
1785+ "type" : "string" ,
1786+ "description" : userDescription ("create a task" ),
1787+ },
1788+ },
1789+ Required : []string {"input" , "template_version_id" },
1790+ },
1791+ },
1792+ UserClientOptional : true ,
1793+ Handler : func (ctx context.Context , deps Deps , args CreateTaskArgs ) (codersdk.Task , error ) {
1794+ if args .Input == "" {
1795+ return codersdk.Task {}, xerrors .New ("input is required" )
1796+ }
1797+
1798+ tvID , err := uuid .Parse (args .TemplateVersionID )
1799+ if err != nil {
1800+ return codersdk.Task {}, xerrors .New ("template_version_id must be a valid UUID" )
1801+ }
1802+
1803+ var tvPresetID uuid.UUID
1804+ if args .TemplateVersionPresetID != "" {
1805+ tvPresetID , err = uuid .Parse (args .TemplateVersionPresetID )
1806+ if err != nil {
1807+ return codersdk.Task {}, xerrors .New ("template_version_preset_id must be a valid UUID" )
1808+ }
1809+ }
1810+
1811+ if args .User == "" {
1812+ args .User = codersdk .Me
1813+ }
1814+
1815+ expClient := codersdk .NewExperimentalClient (deps .coderClient )
1816+ task , err := expClient .CreateTask (ctx , args .User , codersdk.CreateTaskRequest {
1817+ Input : args .Input ,
1818+ TemplateVersionID : tvID ,
1819+ TemplateVersionPresetID : tvPresetID ,
1820+ })
1821+ if err != nil {
1822+ return codersdk.Task {}, xerrors .Errorf ("create task: %w" , err )
1823+ }
1824+
1825+ return task , nil
1826+ },
1827+ }
1828+
1829+ type DeleteTaskArgs struct {
1830+ TaskID string `json:"task_id"`
1831+ }
1832+
1833+ var DeleteTask = Tool [DeleteTaskArgs , codersdk.Response ]{
1834+ Tool : aisdk.Tool {
1835+ Name : ToolNameDeleteTask ,
1836+ Description : `Delete a task.` ,
1837+ Schema : aisdk.Schema {
1838+ Properties : map [string ]any {
1839+ "task_id" : map [string ]any {
1840+ "type" : "string" ,
1841+ "description" : taskIDDescription ("delete" ),
1842+ },
1843+ },
1844+ Required : []string {"task_id" },
1845+ },
1846+ },
1847+ UserClientOptional : true ,
1848+ Handler : func (ctx context.Context , deps Deps , args DeleteTaskArgs ) (codersdk.Response , error ) {
1849+ if args .TaskID == "" {
1850+ return codersdk.Response {}, xerrors .New ("task_id is required" )
1851+ }
1852+
1853+ expClient := codersdk .NewExperimentalClient (deps .coderClient )
1854+
1855+ var owner string
1856+ id , err := uuid .Parse (args .TaskID )
1857+ if err == nil {
1858+ task , err := expClient .TaskByID (ctx , id )
1859+ if err != nil {
1860+ return codersdk.Response {}, xerrors .Errorf ("get task %q: %w" , args .TaskID , err )
1861+ }
1862+ owner = task .OwnerName
1863+ } else {
1864+ ws , err := normalizedNamedWorkspace (ctx , deps .coderClient , args .TaskID )
1865+ if err != nil {
1866+ return codersdk.Response {}, xerrors .Errorf ("get task workspace %q: %w" , args .TaskID , err )
1867+ }
1868+ owner = ws .OwnerName
1869+ id = ws .ID
1870+ }
1871+
1872+ err = expClient .DeleteTask (ctx , owner , id )
1873+ if err != nil {
1874+ return codersdk.Response {}, xerrors .Errorf ("delete task: %w" , err )
1875+ }
1876+
1877+ return codersdk.Response {
1878+ Message : "Task deleted successfully" ,
1879+ }, nil
1880+ },
1881+ }
1882+
1883+ type ListTasksArgs struct {
1884+ Status string `json:"status"`
1885+ User string `json:"user"`
1886+ }
1887+
1888+ type ListTasksResponse struct {
1889+ Tasks []codersdk.Task `json:"tasks"`
1890+ }
1891+
1892+ var ListTasks = Tool [ListTasksArgs , ListTasksResponse ]{
1893+ Tool : aisdk.Tool {
1894+ Name : ToolNameListTasks ,
1895+ Description : `List tasks.` ,
1896+ Schema : aisdk.Schema {
1897+ Properties : map [string ]any {
1898+ "status" : map [string ]any {
1899+ "type" : "string" ,
1900+ "description" : "Optional filter by task status." ,
1901+ },
1902+ "user" : map [string ]any {
1903+ "type" : "string" ,
1904+ "description" : userDescription ("list tasks" ),
1905+ },
1906+ },
1907+ Required : []string {},
1908+ },
1909+ },
1910+ UserClientOptional : true ,
1911+ Handler : func (ctx context.Context , deps Deps , args ListTasksArgs ) (ListTasksResponse , error ) {
1912+ if args .User == "" {
1913+ args .User = codersdk .Me
1914+ }
1915+
1916+ expClient := codersdk .NewExperimentalClient (deps .coderClient )
1917+ tasks , err := expClient .Tasks (ctx , & codersdk.TasksFilter {
1918+ Owner : args .User ,
1919+ Status : args .Status ,
1920+ })
1921+ if err != nil {
1922+ return ListTasksResponse {}, xerrors .Errorf ("list tasks: %w" , err )
1923+ }
1924+
1925+ return ListTasksResponse {
1926+ Tasks : tasks ,
1927+ }, nil
1928+ },
1929+ }
1930+
1931+ type GetTaskStatusArgs struct {
1932+ TaskID string `json:"task_id"`
1933+ }
1934+
1935+ type GetTaskStatusResponse struct {
1936+ Status codersdk.WorkspaceStatus `json:"status"`
1937+ State * codersdk.TaskStateEntry `json:"state"`
1938+ }
1939+
1940+ var GetTaskStatus = Tool [GetTaskStatusArgs , GetTaskStatusResponse ]{
1941+ Tool : aisdk.Tool {
1942+ Name : ToolNameGetTaskStatus ,
1943+ Description : `Get the status of a task.` ,
1944+ Schema : aisdk.Schema {
1945+ Properties : map [string ]any {
1946+ "task_id" : map [string ]any {
1947+ "type" : "string" ,
1948+ "description" : taskIDDescription ("get" ),
1949+ },
1950+ },
1951+ Required : []string {"task_id" },
1952+ },
1953+ },
1954+ UserClientOptional : true ,
1955+ Handler : func (ctx context.Context , deps Deps , args GetTaskStatusArgs ) (GetTaskStatusResponse , error ) {
1956+ if args .TaskID == "" {
1957+ return GetTaskStatusResponse {}, xerrors .New ("task_id is required" )
1958+ }
1959+
1960+ expClient := codersdk .NewExperimentalClient (deps .coderClient )
1961+
1962+ id , err := uuid .Parse (args .TaskID )
1963+ if err != nil {
1964+ ws , err := normalizedNamedWorkspace (ctx , deps .coderClient , args .TaskID )
1965+ if err != nil {
1966+ return GetTaskStatusResponse {}, xerrors .Errorf ("get task workspace %q: %w" , args .TaskID , err )
1967+ }
1968+ id = ws .ID
1969+ }
1970+
1971+ task , err := expClient .TaskByID (ctx , id )
1972+ if err != nil {
1973+ return GetTaskStatusResponse {}, xerrors .Errorf ("get task %q: %w" , args .TaskID , err )
1974+ }
1975+
1976+ return GetTaskStatusResponse {
1977+ Status : task .Status ,
1978+ State : task .CurrentState ,
1979+ }, nil
1980+ },
1981+ }
1982+
1983+ // normalizedNamedWorkspace normalizes the workspace name before getting the
1984+ // workspace by name.
1985+ func normalizedNamedWorkspace (ctx context.Context , client * codersdk.Client , name string ) (codersdk.Workspace , error ) {
1986+ // Maybe namedWorkspace should itself call NormalizeWorkspaceInput?
1987+ return namedWorkspace (ctx , client , NormalizeWorkspaceInput (name ))
1988+ }
1989+
17531990// NormalizeWorkspaceInput converts workspace name input to standard format.
17541991// Handles the following input formats:
17551992// - workspace → workspace
@@ -1810,3 +2047,13 @@ func newAgentConn(ctx context.Context, client *codersdk.Client, workspace string
18102047 }
18112048 return conn , nil
18122049}
2050+
2051+ const workspaceDescription = "The workspace name in the format [owner/]workspace[.agent]. If an owner is not specified, the authenticated user is used."
2052+
2053+ func taskIDDescription (action string ) string {
2054+ return fmt .Sprintf ("ID or workspace identifier in the format [owner/]workspace[.agent] for the task to %s. If an owner is not specified, the authenticated user is used." , action )
2055+ }
2056+
2057+ func userDescription (action string ) string {
2058+ return fmt .Sprintf ("Username or ID of the user for which to %s. Omit or use the `me` keyword to %s for the authenticated user." , action , action )
2059+ }
0 commit comments