@shipfox/api-integration-github 12.6.0 → 12.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +6 -0
- package/dist/core/agent-tools.d.ts.map +1 -1
- package/dist/core/agent-tools.js +91 -2
- package/dist/core/agent-tools.js.map +1 -1
- package/dist/core/github-agent-tool-catalog.d.ts +1 -1
- package/dist/core/github-agent-tool-catalog.d.ts.map +1 -1
- package/dist/core/github-agent-tool-catalog.js +19 -0
- package/dist/core/github-agent-tool-catalog.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/agent-tools.test.ts +134 -0
- package/src/core/agent-tools.ts +108 -4
- package/src/core/github-agent-tool-catalog.ts +35 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -83,6 +83,7 @@ const expectedCatalogRows = [
|
|
|
83
83
|
'get_files',
|
|
84
84
|
'get_commits',
|
|
85
85
|
'get_review_comments',
|
|
86
|
+
'get_review_threads',
|
|
86
87
|
'get_reviews',
|
|
87
88
|
'get_comments',
|
|
88
89
|
'get_check_runs',
|
|
@@ -148,6 +149,14 @@ const expectedCatalogRows = [
|
|
|
148
149
|
requiredScope: [{permission: 'pull_requests', access: 'write'}],
|
|
149
150
|
methods: ['create', 'submit_pending', 'delete_pending'],
|
|
150
151
|
},
|
|
152
|
+
{
|
|
153
|
+
id: 'pull_request_review_thread_write',
|
|
154
|
+
category: 'pull_requests',
|
|
155
|
+
sensitivity: 'write',
|
|
156
|
+
sensitive: false,
|
|
157
|
+
requiredScope: [{permission: 'pull_requests', access: 'write'}],
|
|
158
|
+
methods: ['resolve'],
|
|
159
|
+
},
|
|
151
160
|
{
|
|
152
161
|
id: 'add_comment_to_pending_review',
|
|
153
162
|
category: 'pull_requests',
|
|
@@ -351,6 +360,12 @@ const githubOperationRouteCases = [
|
|
|
351
360
|
args: {pull_number: 1},
|
|
352
361
|
expectedRoute: 'GET /repos/{owner}/{repo}/pulls/{pull_number}/comments',
|
|
353
362
|
},
|
|
363
|
+
{
|
|
364
|
+
toolId: 'pull_request_read',
|
|
365
|
+
method: 'get_review_threads',
|
|
366
|
+
args: {pull_number: 1},
|
|
367
|
+
expectedRoute: 'POST /graphql',
|
|
368
|
+
},
|
|
354
369
|
{
|
|
355
370
|
toolId: 'pull_request_read',
|
|
356
371
|
method: 'get_reviews',
|
|
@@ -429,6 +444,12 @@ const githubOperationRouteCases = [
|
|
|
429
444
|
runtimeInjectedProperties: ['review_id'],
|
|
430
445
|
expectedRoute: 'DELETE /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}',
|
|
431
446
|
},
|
|
447
|
+
{
|
|
448
|
+
toolId: 'pull_request_review_thread_write',
|
|
449
|
+
method: 'resolve',
|
|
450
|
+
args: {thread_id: 'PRRT_kwDOExample'},
|
|
451
|
+
expectedRoute: 'POST /graphql',
|
|
452
|
+
},
|
|
432
453
|
{
|
|
433
454
|
toolId: 'add_comment_to_pending_review',
|
|
434
455
|
args: {pull_number: 1, path: 'src/index.ts', body: 'Comment'},
|
|
@@ -663,6 +684,7 @@ describe('github agent tool catalog', () => {
|
|
|
663
684
|
{properties: {method: {const: 'get_files'}}, required: []},
|
|
664
685
|
{properties: {method: {const: 'get_commits'}}, required: []},
|
|
665
686
|
{properties: {method: {const: 'get_review_comments'}}, required: []},
|
|
687
|
+
{properties: {method: {const: 'get_review_threads'}}, required: []},
|
|
666
688
|
{properties: {method: {const: 'get_reviews'}}, required: []},
|
|
667
689
|
{properties: {method: {const: 'get_comments'}}, required: []},
|
|
668
690
|
{properties: {method: {const: 'get_check_runs'}}, required: ['ref']},
|
|
@@ -841,6 +863,104 @@ describe('github agent tool catalog', () => {
|
|
|
841
863
|
});
|
|
842
864
|
});
|
|
843
865
|
|
|
866
|
+
it('reads pull request review threads through GraphQL', async () => {
|
|
867
|
+
const request = vi.fn();
|
|
868
|
+
const data = {
|
|
869
|
+
repository: {
|
|
870
|
+
pullRequest: {
|
|
871
|
+
reviewThreads: {
|
|
872
|
+
nodes: [
|
|
873
|
+
{
|
|
874
|
+
id: 'PRRT_kwDOExample',
|
|
875
|
+
isResolved: false,
|
|
876
|
+
comments: {
|
|
877
|
+
nodes: [
|
|
878
|
+
{
|
|
879
|
+
id: 'PRRC_kwDOExample',
|
|
880
|
+
databaseId: 7,
|
|
881
|
+
body: 'Please handle this.',
|
|
882
|
+
author: {login: 'reviewer'},
|
|
883
|
+
path: 'src/index.ts',
|
|
884
|
+
line: 42,
|
|
885
|
+
},
|
|
886
|
+
],
|
|
887
|
+
},
|
|
888
|
+
},
|
|
889
|
+
],
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
};
|
|
894
|
+
const graphql = vi.fn().mockResolvedValueOnce(data);
|
|
895
|
+
const provider = createAgentToolsProvider({request, graphql});
|
|
896
|
+
const session = await provider.openSession({
|
|
897
|
+
connection: connection(),
|
|
898
|
+
tools: [pullRequestReadTool()],
|
|
899
|
+
scope: undefined,
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
const result = await session.call({
|
|
903
|
+
toolId: 'pull_request_read',
|
|
904
|
+
arguments: {
|
|
905
|
+
method: 'get_review_threads',
|
|
906
|
+
owner: 'shipfox',
|
|
907
|
+
repo: 'platform',
|
|
908
|
+
pull_number: 2,
|
|
909
|
+
cursor: 'cursor-1',
|
|
910
|
+
},
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
expect(request).not.toHaveBeenCalled();
|
|
914
|
+
expect(graphql).toHaveBeenCalledWith(
|
|
915
|
+
expect.stringContaining('reviewThreads(first: 100, after: $after)'),
|
|
916
|
+
{owner: 'shipfox', repo: 'platform', pullNumber: 2, after: 'cursor-1'},
|
|
917
|
+
);
|
|
918
|
+
const query = graphql.mock.calls[0]?.[0];
|
|
919
|
+
expect(query).toContain('isResolved');
|
|
920
|
+
expect(query).toContain('author');
|
|
921
|
+
expect(query).toContain('path');
|
|
922
|
+
expect(query).toContain('line');
|
|
923
|
+
expect(result).toEqual({
|
|
924
|
+
content: [{type: 'text', text: JSON.stringify(data)}],
|
|
925
|
+
structuredContent: data,
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
it('resolves a pull request review thread through GraphQL', async () => {
|
|
930
|
+
const request = vi.fn();
|
|
931
|
+
const data = {
|
|
932
|
+
resolveReviewThread: {
|
|
933
|
+
thread: {id: 'PRRT_kwDOExample', isResolved: true},
|
|
934
|
+
},
|
|
935
|
+
};
|
|
936
|
+
const graphql = vi.fn().mockResolvedValueOnce(data);
|
|
937
|
+
const provider = createAgentToolsProvider({request, graphql});
|
|
938
|
+
const session = await provider.openSession({
|
|
939
|
+
connection: connection(),
|
|
940
|
+
tools: [pullRequestReviewThreadWriteTool()],
|
|
941
|
+
scope: undefined,
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
const result = await session.call({
|
|
945
|
+
toolId: 'pull_request_review_thread_write',
|
|
946
|
+
arguments: {
|
|
947
|
+
method: 'resolve',
|
|
948
|
+
owner: 'shipfox',
|
|
949
|
+
repo: 'platform',
|
|
950
|
+
thread_id: 'PRRT_kwDOExample',
|
|
951
|
+
},
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
expect(request).not.toHaveBeenCalled();
|
|
955
|
+
expect(graphql).toHaveBeenCalledWith(expect.stringContaining('resolveReviewThread'), {
|
|
956
|
+
input: {threadId: 'PRRT_kwDOExample'},
|
|
957
|
+
});
|
|
958
|
+
expect(result).toEqual({
|
|
959
|
+
content: [{type: 'text', text: JSON.stringify(data)}],
|
|
960
|
+
structuredContent: data,
|
|
961
|
+
});
|
|
962
|
+
});
|
|
963
|
+
|
|
844
964
|
it('projects issue comment reactions through the provider session', async () => {
|
|
845
965
|
const request = vi.fn(() => Promise.resolve({data: {id: 7}}));
|
|
846
966
|
const result = await callGithubToolWithRequest(
|
|
@@ -1546,6 +1666,20 @@ function pendingReviewTool() {
|
|
|
1546
1666
|
return tool;
|
|
1547
1667
|
}
|
|
1548
1668
|
|
|
1669
|
+
function pullRequestReadTool() {
|
|
1670
|
+
const tool = githubAgentToolCatalog.find((entry) => entry.id === 'pull_request_read');
|
|
1671
|
+
if (!tool) throw new Error('Missing pull_request_read tool');
|
|
1672
|
+
return tool;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
function pullRequestReviewThreadWriteTool() {
|
|
1676
|
+
const tool = githubAgentToolCatalog.find(
|
|
1677
|
+
(entry) => entry.id === 'pull_request_review_thread_write',
|
|
1678
|
+
);
|
|
1679
|
+
if (!tool) throw new Error('Missing pull_request_review_thread_write tool');
|
|
1680
|
+
return tool;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1549
1683
|
function connection() {
|
|
1550
1684
|
return {
|
|
1551
1685
|
id: 'connection-1',
|
package/src/core/agent-tools.ts
CHANGED
|
@@ -78,6 +78,63 @@ const ADD_PENDING_REVIEW_COMMENT_MUTATION = `
|
|
|
78
78
|
}
|
|
79
79
|
`;
|
|
80
80
|
|
|
81
|
+
const GET_PULL_REQUEST_REVIEW_THREADS_QUERY = `
|
|
82
|
+
query GetPullRequestReviewThreads(
|
|
83
|
+
$owner: String!
|
|
84
|
+
$repo: String!
|
|
85
|
+
$pullNumber: Int!
|
|
86
|
+
$after: String
|
|
87
|
+
) {
|
|
88
|
+
repository(owner: $owner, name: $repo) {
|
|
89
|
+
pullRequest(number: $pullNumber) {
|
|
90
|
+
reviewThreads(first: 100, after: $after) {
|
|
91
|
+
nodes {
|
|
92
|
+
id
|
|
93
|
+
isResolved
|
|
94
|
+
comments(first: 100) {
|
|
95
|
+
nodes {
|
|
96
|
+
id
|
|
97
|
+
databaseId
|
|
98
|
+
body
|
|
99
|
+
author {
|
|
100
|
+
login
|
|
101
|
+
}
|
|
102
|
+
path
|
|
103
|
+
line
|
|
104
|
+
side
|
|
105
|
+
startLine
|
|
106
|
+
startSide
|
|
107
|
+
createdAt
|
|
108
|
+
updatedAt
|
|
109
|
+
url
|
|
110
|
+
}
|
|
111
|
+
pageInfo {
|
|
112
|
+
hasNextPage
|
|
113
|
+
endCursor
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
pageInfo {
|
|
118
|
+
hasNextPage
|
|
119
|
+
endCursor
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const RESOLVE_PULL_REQUEST_REVIEW_THREAD_MUTATION = `
|
|
128
|
+
mutation ResolvePullRequestReviewThread($input: ResolveReviewThreadInput!) {
|
|
129
|
+
resolveReviewThread(input: $input) {
|
|
130
|
+
thread {
|
|
131
|
+
id
|
|
132
|
+
isResolved
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
|
|
81
138
|
export class GithubAgentToolsProvider
|
|
82
139
|
implements
|
|
83
140
|
AgentToolsProvider<
|
|
@@ -145,11 +202,17 @@ export class GithubAgentToolsProvider
|
|
|
145
202
|
|
|
146
203
|
if (operation.kind === 'graphql') {
|
|
147
204
|
const data = await mapGithubError(() =>
|
|
148
|
-
|
|
205
|
+
executeGithubGraphqlOperation(
|
|
206
|
+
client,
|
|
207
|
+
tool.id as GithubAgentToolId,
|
|
208
|
+
method,
|
|
209
|
+
operation.parameters,
|
|
210
|
+
),
|
|
149
211
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
212
|
+
if (data === undefined && tool.id === 'add_comment_to_pending_review') {
|
|
213
|
+
return githubToolError(NO_PENDING_REVIEW_MESSAGE, 'provider-rejected');
|
|
214
|
+
}
|
|
215
|
+
return githubToolResult(tool.id as GithubAgentToolId, data);
|
|
153
216
|
}
|
|
154
217
|
|
|
155
218
|
const operationParameters = await mapGithubError(() =>
|
|
@@ -322,6 +385,8 @@ export function githubOperationRoute(
|
|
|
322
385
|
return `GET ${repoPath}/pulls/${pull}/commits`;
|
|
323
386
|
case 'pull_request_read.get_review_comments':
|
|
324
387
|
return `GET ${repoPath}/pulls/${pull}/comments`;
|
|
388
|
+
case 'pull_request_read.get_review_threads':
|
|
389
|
+
return GITHUB_GRAPHQL_ROUTE;
|
|
325
390
|
case 'pull_request_read.get_reviews':
|
|
326
391
|
return `GET ${repoPath}/pulls/${pull}/reviews`;
|
|
327
392
|
case 'pull_request_read.get_comments':
|
|
@@ -350,6 +415,8 @@ export function githubOperationRoute(
|
|
|
350
415
|
return `POST ${repoPath}/pulls/${pull}/reviews/{review_id}/events`;
|
|
351
416
|
case 'pull_request_review_write.delete_pending':
|
|
352
417
|
return `DELETE ${repoPath}/pulls/${pull}/reviews/{review_id}`;
|
|
418
|
+
case 'pull_request_review_thread_write.resolve':
|
|
419
|
+
return GITHUB_GRAPHQL_ROUTE;
|
|
353
420
|
case 'add_comment_to_pending_review.':
|
|
354
421
|
return GITHUB_GRAPHQL_ROUTE;
|
|
355
422
|
case 'actions_list.list_workflows':
|
|
@@ -423,6 +490,43 @@ async function addCommentToPendingReview(
|
|
|
423
490
|
return await client.graphql(ADD_PENDING_REVIEW_COMMENT_MUTATION, {input});
|
|
424
491
|
}
|
|
425
492
|
|
|
493
|
+
async function executeGithubGraphqlOperation(
|
|
494
|
+
client: GithubToolClient,
|
|
495
|
+
toolId: GithubAgentToolId,
|
|
496
|
+
method: string | undefined,
|
|
497
|
+
parameters: Record<string, unknown>,
|
|
498
|
+
): Promise<unknown | undefined> {
|
|
499
|
+
if (client.graphql === undefined) {
|
|
500
|
+
throw new GithubIntegrationProviderError(
|
|
501
|
+
'malformed-provider-response',
|
|
502
|
+
'GitHub client does not support GraphQL operations',
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
switch (`${toolId}.${method ?? ''}`) {
|
|
507
|
+
case 'pull_request_read.get_review_threads': {
|
|
508
|
+
const variables: Record<string, unknown> = {
|
|
509
|
+
owner: parameters.owner,
|
|
510
|
+
repo: parameters.repo,
|
|
511
|
+
pullNumber: parameters.pull_number,
|
|
512
|
+
};
|
|
513
|
+
if (typeof parameters.cursor === 'string') variables.after = parameters.cursor;
|
|
514
|
+
return await client.graphql(GET_PULL_REQUEST_REVIEW_THREADS_QUERY, variables);
|
|
515
|
+
}
|
|
516
|
+
case 'pull_request_review_thread_write.resolve':
|
|
517
|
+
return await client.graphql(RESOLVE_PULL_REQUEST_REVIEW_THREAD_MUTATION, {
|
|
518
|
+
input: {threadId: parameters.thread_id},
|
|
519
|
+
});
|
|
520
|
+
case 'add_comment_to_pending_review.':
|
|
521
|
+
return await addCommentToPendingReview(client, parameters);
|
|
522
|
+
default:
|
|
523
|
+
throw new GithubIntegrationProviderError(
|
|
524
|
+
'malformed-provider-response',
|
|
525
|
+
'GitHub operation does not support GraphQL operations',
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
426
530
|
export function projectGithubOperationParameters(
|
|
427
531
|
toolId: GithubAgentToolId,
|
|
428
532
|
method: string | undefined,
|
|
@@ -174,6 +174,13 @@ const pullRequestReadMethods = [
|
|
|
174
174
|
false,
|
|
175
175
|
scopes.pullRequestsRead,
|
|
176
176
|
),
|
|
177
|
+
method(
|
|
178
|
+
'get_review_threads',
|
|
179
|
+
'Get review threads, their resolution state, and comments for a specific pull request.',
|
|
180
|
+
'read',
|
|
181
|
+
false,
|
|
182
|
+
scopes.pullRequestsRead,
|
|
183
|
+
),
|
|
177
184
|
method(
|
|
178
185
|
'get_reviews',
|
|
179
186
|
'Get reviews for a specific pull request.',
|
|
@@ -221,6 +228,16 @@ const pullRequestReviewWriteMethods = [
|
|
|
221
228
|
),
|
|
222
229
|
] as const satisfies readonly GithubAgentToolCatalogMethod[];
|
|
223
230
|
|
|
231
|
+
const pullRequestReviewThreadWriteMethods = [
|
|
232
|
+
method(
|
|
233
|
+
'resolve',
|
|
234
|
+
'Resolve a pull request review thread.',
|
|
235
|
+
'write',
|
|
236
|
+
false,
|
|
237
|
+
scopes.pullRequestsWrite,
|
|
238
|
+
),
|
|
239
|
+
] as const satisfies readonly GithubAgentToolCatalogMethod[];
|
|
240
|
+
|
|
224
241
|
const actionsListMethods = [
|
|
225
242
|
method('list_workflows', 'List workflows in a repository.', 'read', false, scopes.actionsRead),
|
|
226
243
|
method(
|
|
@@ -472,6 +489,7 @@ export const githubAgentToolCatalog = [
|
|
|
472
489
|
methodRequiredSchema('get_files', []),
|
|
473
490
|
methodRequiredSchema('get_commits', []),
|
|
474
491
|
methodRequiredSchema('get_review_comments', []),
|
|
492
|
+
methodRequiredSchema('get_review_threads', []),
|
|
475
493
|
methodRequiredSchema('get_reviews', []),
|
|
476
494
|
methodRequiredSchema('get_comments', []),
|
|
477
495
|
methodRequiredSchema('get_check_runs', ['ref']),
|
|
@@ -666,6 +684,23 @@ export const githubAgentToolCatalog = [
|
|
|
666
684
|
),
|
|
667
685
|
outputSchema: openObjectSchema('Pull request review write result'),
|
|
668
686
|
}),
|
|
687
|
+
tool({
|
|
688
|
+
id: 'pull_request_review_thread_write',
|
|
689
|
+
category: 'pull_requests',
|
|
690
|
+
description: 'Resolve review threads on a pull request in a GitHub repository.',
|
|
691
|
+
methods: pullRequestReviewThreadWriteMethods,
|
|
692
|
+
inputSchema: repositoryInputSchema(
|
|
693
|
+
{
|
|
694
|
+
method: methodSchema(
|
|
695
|
+
pullRequestReviewThreadWriteMethods,
|
|
696
|
+
'The write operation to perform on a pull request review thread',
|
|
697
|
+
),
|
|
698
|
+
thread_id: stringSchema('The node ID of the review thread'),
|
|
699
|
+
},
|
|
700
|
+
['method', 'thread_id'],
|
|
701
|
+
),
|
|
702
|
+
outputSchema: openObjectSchema('Pull request review thread write result'),
|
|
703
|
+
}),
|
|
669
704
|
tool({
|
|
670
705
|
id: 'add_comment_to_pending_review',
|
|
671
706
|
category: 'pull_requests',
|