@@ -50,6 +50,10 @@ const (
50
50
ToolNameWorkspaceEditFile = "coder_workspace_edit_file"
51
51
ToolNameWorkspaceEditFiles = "coder_workspace_edit_files"
52
52
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"
53
57
)
54
58
55
59
func NewDeps (client * codersdk.Client ,opts ... func (* Deps )) (Deps ,error ) {
@@ -223,6 +227,10 @@ var All = []GenericTool{
223
227
WorkspaceEditFile .Generic (),
224
228
WorkspaceEditFiles .Generic (),
225
229
WorkspacePortForward .Generic (),
230
+ CreateTask .Generic (),
231
+ DeleteTask .Generic (),
232
+ ListTasks .Generic (),
233
+ GetTaskStatus .Generic (),
226
234
}
227
235
228
236
type ReportTaskArgs struct {
@@ -344,7 +352,7 @@ is provisioned correctly and the agent can connect to the control plane.
344
352
Properties :map [string ]any {
345
353
"user" :map [string ]any {
346
354
"type" :"string" ,
347
- "description" :"Username or ID of the user to createthe workspace for. Use the `me` keyword to create a workspace for the authenticated user." ,
355
+ "description" :userDescription ( " create a workspace" ) ,
348
356
},
349
357
"template_version_id" :map [string ]any {
350
358
"type" :"string" ,
@@ -1393,8 +1401,6 @@ type WorkspaceLSResponse struct {
1393
1401
Contents []WorkspaceLSFile `json:"contents"`
1394
1402
}
1395
1403
1396
- const workspaceDescription = "The workspace name in the format [owner/]workspace[.agent]. If an owner is not specified, the authenticated user is used."
1397
-
1398
1404
var WorkspaceLS = Tool [WorkspaceLSArgs ,WorkspaceLSResponse ]{
1399
1405
Tool : aisdk.Tool {
1400
1406
Name :ToolNameWorkspaceLS ,
@@ -1750,6 +1756,237 @@ var WorkspacePortForward = Tool[WorkspacePortForwardArgs, WorkspacePortForwardRe
1750
1756
},
1751
1757
}
1752
1758
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
+
1753
1990
// NormalizeWorkspaceInput converts workspace name input to standard format.
1754
1991
// Handles the following input formats:
1755
1992
// - workspace → workspace
@@ -1810,3 +2047,13 @@ func newAgentConn(ctx context.Context, client *codersdk.Client, workspace string
1810
2047
}
1811
2048
return conn ,nil
1812
2049
}
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
+ }