Skip to content

Commit dc0817a

Browse files
fix: address agent tasks schema review
1 parent 41b1ac1 commit dc0817a

4 files changed

Lines changed: 221 additions & 61 deletions

File tree

github/agent_tasks.go

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,28 @@ type AgentTask struct {
2828
Name *string `json:"name,omitempty"`
2929
Creator *User `json:"creator,omitempty"`
3030
CreatorType *string `json:"creator_type,omitempty"`
31-
Owner *User `json:"owner,omitempty"`
32-
Repository *Repository `json:"repository,omitempty"`
31+
Owner *AgentTaskOwner `json:"owner,omitempty"`
32+
Repository *AgentTaskRepository `json:"repository,omitempty"`
3333
State string `json:"state"`
3434
SessionCount *int `json:"session_count,omitempty"`
3535
Artifacts []*AgentTaskArtifact `json:"artifacts,omitempty"`
3636
ArchivedAt *Timestamp `json:"archived_at,omitempty"`
3737
CreatedAt Timestamp `json:"created_at"`
3838
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
3939
Sessions []*AgentTaskSession `json:"sessions,omitempty"`
40+
41+
// Deprecated: UserCollaborators is deprecated by GitHub.
42+
UserCollaborators []*User `json:"user_collaborators,omitempty"`
43+
}
44+
45+
// AgentTaskOwner represents an agent task owner.
46+
type AgentTaskOwner struct {
47+
ID *int64 `json:"id,omitempty"`
48+
}
49+
50+
// AgentTaskRepository represents an agent task repository.
51+
type AgentTaskRepository struct {
52+
ID *int64 `json:"id,omitempty"`
4053
}
4154

4255
// AgentTaskArtifact represents an artifact produced by an agent task.
@@ -48,25 +61,27 @@ type AgentTaskArtifact struct {
4861

4962
// AgentTaskSession represents a session associated with an agent task.
5063
type AgentTaskSession struct {
51-
ID string `json:"id"`
52-
Name *string `json:"name,omitempty"`
53-
User *User `json:"user,omitempty"`
54-
Owner *User `json:"owner,omitempty"`
55-
Repository *Repository `json:"repository,omitempty"`
56-
TaskID *string `json:"task_id,omitempty"`
57-
State string `json:"state"`
58-
CreatedAt Timestamp `json:"created_at"`
59-
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
60-
CompletedAt *Timestamp `json:"completed_at,omitempty"`
61-
Prompt *string `json:"prompt,omitempty"`
62-
HeadRef *string `json:"head_ref,omitempty"`
63-
BaseRef *string `json:"base_ref,omitempty"`
64-
Model *string `json:"model,omitempty"`
64+
ID string `json:"id"`
65+
Name *string `json:"name,omitempty"`
66+
User *User `json:"user,omitempty"`
67+
Owner *AgentTaskOwner `json:"owner,omitempty"`
68+
Repository *AgentTaskRepository `json:"repository,omitempty"`
69+
TaskID *string `json:"task_id,omitempty"`
70+
State string `json:"state"`
71+
CreatedAt Timestamp `json:"created_at"`
72+
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
73+
CompletedAt *Timestamp `json:"completed_at,omitempty"`
74+
Prompt *string `json:"prompt,omitempty"`
75+
HeadRef *string `json:"head_ref,omitempty"`
76+
BaseRef *string `json:"base_ref,omitempty"`
77+
Model *string `json:"model,omitempty"`
6578
}
6679

6780
// AgentTaskList represents a list of agent tasks.
6881
type AgentTaskList struct {
69-
Tasks []*AgentTask `json:"tasks"`
82+
Tasks []*AgentTask `json:"tasks"`
83+
TotalActiveCount *int `json:"total_active_count,omitempty"`
84+
TotalArchivedCount *int `json:"total_archived_count,omitempty"`
7085
}
7186

7287
// AgentTaskListOptions specifies optional parameters to AgentTasksService.List.
@@ -84,7 +99,7 @@ type AgentTaskListOptions struct {
8499
IsArchived bool `url:"is_archived,omitempty"`
85100

86101
// Since filters tasks updated at or after this time.
87-
Since time.Time `url:"since,omitempty"`
102+
Since *time.Time `url:"since,omitempty"`
88103

89104
ListOptions
90105
}
@@ -97,7 +112,7 @@ type AgentTaskListByRepoOptions struct {
97112
CreatorID int64 `url:"creator_id,omitempty"`
98113
}
99114

100-
// CreateAgentTaskOptions represents the parameters for creating an agent task.
115+
// CreateAgentTaskRequest represents the parameters for creating an agent task.
101116
type CreateAgentTaskRequest struct {
102117
// Prompt is the user's prompt for the agent.
103118
Prompt string `json:"prompt"`
@@ -114,6 +129,8 @@ type CreateAgentTaskRequest struct {
114129

115130
// ListByRepo lists tasks for a repository.
116131
//
132+
// This endpoint is in public preview and is subject to change.
133+
//
117134
// GitHub API docs: https://docs.github.com/rest/agent-tasks/agent-tasks?apiVersion=2026-03-10#list-tasks-for-repository
118135
//
119136
//meta:operation GET /agents/repos/{owner}/{repo}/tasks
@@ -140,10 +157,12 @@ func (s *AgentTasksService) ListByRepo(ctx context.Context, owner, repo string,
140157

141158
// Create starts a new Copilot cloud agent task for a repository.
142159
//
160+
// This endpoint is in public preview and is subject to change.
161+
//
143162
// GitHub API docs: https://docs.github.com/rest/agent-tasks/agent-tasks?apiVersion=2026-03-10#start-a-task
144163
//
145164
//meta:operation POST /agents/repos/{owner}/{repo}/tasks
146-
func (s *AgentTasksService) Create(ctx context.Context, owner, repo string, req CreateAgentTaskRequest) (*AgentTask, *Response, error) {
165+
func (s *AgentTasksService) Create(ctx context.Context, owner, repo string, opts *CreateAgentTaskRequest) (*AgentTask, *Response, error) {
147166
u := fmt.Sprintf("agents/repos/%v/%v/tasks", owner, repo)
148167

149168
req, err := s.client.NewRequest(ctx, "POST", u, opts, WithVersion(agentTasksAPIVersion))
@@ -162,10 +181,12 @@ func (s *AgentTasksService) Create(ctx context.Context, owner, repo string, req
162181

163182
// GetByRepoAndID gets a repository task by ID.
164183
//
184+
// This endpoint is in public preview and is subject to change.
185+
//
165186
// GitHub API docs: https://docs.github.com/rest/agent-tasks/agent-tasks?apiVersion=2026-03-10#get-a-task-by-repo
166187
//
167188
//meta:operation GET /agents/repos/{owner}/{repo}/tasks/{task_id}
168-
func (s *AgentTasksService) GetByRepo(ctx context.Context, owner, repo, taskID string) (*AgentTask, *Response, error) {
189+
func (s *AgentTasksService) GetByRepoAndID(ctx context.Context, owner, repo, taskID string) (*AgentTask, *Response, error) {
169190
u := fmt.Sprintf("agents/repos/%v/%v/tasks/%v", owner, repo, taskID)
170191

171192
req, err := s.client.NewRequest(ctx, "GET", u, nil, WithVersion(agentTasksAPIVersion))
@@ -184,6 +205,8 @@ func (s *AgentTasksService) GetByRepo(ctx context.Context, owner, repo, taskID s
184205

185206
// List lists tasks for the authenticated user.
186207
//
208+
// This endpoint is in public preview and is subject to change.
209+
//
187210
// GitHub API docs: https://docs.github.com/rest/agent-tasks/agent-tasks?apiVersion=2026-03-10#list-tasks
188211
//
189212
//meta:operation GET /agents/tasks
@@ -210,6 +233,8 @@ func (s *AgentTasksService) List(ctx context.Context, opts *AgentTaskListOptions
210233

211234
// Get gets a task by ID for the authenticated user.
212235
//
236+
// This endpoint is in public preview and is subject to change.
237+
//
213238
// GitHub API docs: https://docs.github.com/rest/agent-tasks/agent-tasks?apiVersion=2026-03-10#get-a-task-by-id
214239
//
215240
//meta:operation GET /agents/tasks/{task_id}

github/agent_tasks_test.go

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func agentTaskJSON(includeSessions bool) string {
2929
"name": "Fix the login button on the homepage",
3030
"creator": { "id": 1 },
3131
"creator_type": "user",
32+
"user_collaborators": [{ "id": 3 }],
3233
"owner": { "id": 2 },
3334
"repository": { "id": 1296269 },
3435
"state": "completed",
@@ -72,14 +73,17 @@ func agentTask(includeSessions bool) *AgentTask {
7273
updatedAt := &Timestamp{time.Date(2025, time.January, 1, 1, 0, 0, 0, time.UTC)}
7374

7475
task := &AgentTask{
75-
ID: agentTaskID,
76-
URL: Ptr("https://api.github.com/agents/repos/octocat/hello-world/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
77-
HTMLURL: Ptr("https://github.com/octocat/hello-world/copilot/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
78-
Name: Ptr("Fix the login button on the homepage"),
79-
Creator: &User{ID: Ptr(int64(1))},
80-
CreatorType: Ptr("user"),
81-
Owner: &User{ID: Ptr(int64(2))},
82-
Repository: &Repository{ID: Ptr(int64(1296269))},
76+
ID: agentTaskID,
77+
URL: Ptr("https://api.github.com/agents/repos/octocat/hello-world/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
78+
HTMLURL: Ptr("https://github.com/octocat/hello-world/copilot/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
79+
Name: Ptr("Fix the login button on the homepage"),
80+
Creator: &User{ID: Ptr(int64(1))},
81+
CreatorType: Ptr("user"),
82+
UserCollaborators: []*User{
83+
{ID: Ptr(int64(3))},
84+
},
85+
Owner: &AgentTaskOwner{ID: Ptr(int64(2))},
86+
Repository: &AgentTaskRepository{ID: Ptr(int64(1296269))},
8387
State: "completed",
8488
SessionCount: Ptr(1),
8589
Artifacts: []*AgentTaskArtifact{
@@ -99,8 +103,8 @@ func agentTask(includeSessions bool) *AgentTask {
99103
ID: agentTaskSessionID,
100104
Name: Ptr("Fix the login button on the homepage"),
101105
User: &User{ID: Ptr(int64(1))},
102-
Owner: &User{ID: Ptr(int64(2))},
103-
Repository: &Repository{ID: Ptr(int64(1296269))},
106+
Owner: &AgentTaskOwner{ID: Ptr(int64(2))},
107+
Repository: &AgentTaskRepository{ID: Ptr(int64(1296269))},
104108
TaskID: Ptr(agentTaskID),
105109
State: "completed",
106110
CreatedAt: *createdAt,
@@ -139,7 +143,7 @@ func TestAgentTasksService_ListByRepo(t *testing.T) {
139143
"state": "queued,completed",
140144
})
141145
w.Header().Set("Link", `<https://api.github.com/agents/repos/o/r/tasks?page=3>; rel="next"`)
142-
fmt.Fprintf(w, `{"tasks":[%v]}`, agentTaskJSON(false))
146+
fmt.Fprintf(w, `{"tasks":[%v],"total_active_count":5,"total_archived_count":2}`, agentTaskJSON(false))
143147
})
144148

145149
opts := &AgentTaskListByRepoOptions{
@@ -160,7 +164,11 @@ func TestAgentTasksService_ListByRepo(t *testing.T) {
160164
t.Fatalf("AgentTasks.ListByRepo returned error: %v", err)
161165
}
162166

163-
want := &AgentTaskList{Tasks: []*AgentTask{agentTask(false)}}
167+
want := &AgentTaskList{
168+
Tasks: []*AgentTask{agentTask(false)},
169+
TotalActiveCount: Ptr(5),
170+
TotalArchivedCount: Ptr(2),
171+
}
164172
if diff := cmp.Diff(want, tasks, cmpJSONRawMessageComparator()); diff != "" {
165173
t.Errorf("AgentTasks.ListByRepo mismatch (-want +got):\n%v", diff)
166174
}
@@ -187,7 +195,7 @@ func TestAgentTasksService_Create(t *testing.T) {
187195
t.Parallel()
188196
client, mux, _ := setup(t)
189197

190-
input := &CreateAgentTaskOptions{
198+
input := &CreateAgentTaskRequest{
191199
Prompt: "Fix the login button on the homepage",
192200
Model: Ptr("gpt-5.3-codex"),
193201
CreatePullRequest: Ptr(true),
@@ -278,7 +286,7 @@ func TestAgentTasksService_List(t *testing.T) {
278286
"state": "completed",
279287
})
280288
w.Header().Set("Link", `<https://api.github.com/agents/tasks?page=3>; rel="next"`)
281-
fmt.Fprintf(w, `{"tasks":[%v]}`, agentTaskJSON(false))
289+
fmt.Fprintf(w, `{"tasks":[%v],"total_active_count":5,"total_archived_count":2}`, agentTaskJSON(false))
282290
})
283291

284292
opts := &AgentTaskListOptions{
@@ -296,7 +304,11 @@ func TestAgentTasksService_List(t *testing.T) {
296304
t.Fatalf("AgentTasks.List returned error: %v", err)
297305
}
298306

299-
want := &AgentTaskList{Tasks: []*AgentTask{agentTask(false)}}
307+
want := &AgentTaskList{
308+
Tasks: []*AgentTask{agentTask(false)},
309+
TotalActiveCount: Ptr(5),
310+
TotalArchivedCount: Ptr(2),
311+
}
300312
if diff := cmp.Diff(want, tasks, cmpJSONRawMessageComparator()); diff != "" {
301313
t.Errorf("AgentTasks.List mismatch (-want +got):\n%v", diff)
302314
}
@@ -372,6 +384,26 @@ func TestAgentTaskArtifact_Marshal(t *testing.T) {
372384
testJSONMarshal(t, u, want, cmpJSONRawMessageComparator())
373385
}
374386

387+
func TestAgentTaskOwner_Marshal(t *testing.T) {
388+
t.Parallel()
389+
testJSONMarshal(t, &AgentTaskOwner{}, "{}")
390+
391+
u := &AgentTaskOwner{ID: Ptr(int64(2))}
392+
want := `{"id":2}`
393+
394+
testJSONMarshal(t, u, want)
395+
}
396+
397+
func TestAgentTaskRepository_Marshal(t *testing.T) {
398+
t.Parallel()
399+
testJSONMarshal(t, &AgentTaskRepository{}, "{}")
400+
401+
u := &AgentTaskRepository{ID: Ptr(int64(1296269))}
402+
want := `{"id":1296269}`
403+
404+
testJSONMarshal(t, u, want)
405+
}
406+
375407
func TestAgentTaskSession_Marshal(t *testing.T) {
376408
t.Parallel()
377409
testJSONMarshal(t, &AgentTaskSession{}, `{"id":"","state":"","created_at":"0001-01-01T00:00:00Z"}`)
@@ -399,19 +431,27 @@ func TestAgentTaskSession_Marshal(t *testing.T) {
399431

400432
func TestAgentTaskList_Marshal(t *testing.T) {
401433
t.Parallel()
402-
testJSONMarshal(t, &AgentTaskList{}, "{}")
434+
testJSONMarshal(t, &AgentTaskList{}, `{"tasks":null}`)
403435

404-
u := &AgentTaskList{Tasks: []*AgentTask{agentTask(false)}}
405-
want := `{"tasks":[` + agentTaskMarshalJSON(false) + `]}`
436+
u := &AgentTaskList{
437+
Tasks: []*AgentTask{agentTask(false)},
438+
TotalActiveCount: Ptr(5),
439+
TotalArchivedCount: Ptr(2),
440+
}
441+
want := `{
442+
"tasks":[` + agentTaskMarshalJSON(false) + `],
443+
"total_active_count": 5,
444+
"total_archived_count": 2
445+
}`
406446

407447
testJSONMarshal(t, u, want, cmpJSONRawMessageComparator())
408448
}
409449

410-
func TestCreateAgentTaskOptions_Marshal(t *testing.T) {
450+
func TestCreateAgentTaskRequest_Marshal(t *testing.T) {
411451
t.Parallel()
412-
testJSONMarshal(t, &CreateAgentTaskOptions{}, `{"prompt": ""}`)
452+
testJSONMarshal(t, &CreateAgentTaskRequest{}, `{"prompt": ""}`)
413453

414-
u := &CreateAgentTaskOptions{
454+
u := &CreateAgentTaskRequest{
415455
Prompt: "Fix the login button on the homepage",
416456
Model: Ptr("gpt-5.3-codex"),
417457
CreatePullRequest: Ptr(true),

0 commit comments

Comments
 (0)