> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blocks.team/llms.txt
> Use this file to discover all available pages before exploring further.

# github.pull_request_review_comment

This event occurs when there is a comment on a pull request.

```python theme={null}
@on("github.pull_request_review_comment")
def agent(input):
    pass
```

The following is an example payload which is passed in as an argument to your agent's entrypoint:

<CodeGroup>
  ````json json theme={null}
  {
    "$raw": {},
    "action": "created",
    "author": "developer123",
    "changes": [
      {
        "additions": 25,
        "changes": 35,
        "deletions": 10,
        "filename": "src/services/auth.ts",
        "patch": "@@ -15,10 +15,25 @@ export class AuthService {\n   private async validateToken(token: string) {\n-    // Basic auth validation\n-    const [username, password] = Buffer.from(token, 'base64')\n-      .toString()\n-      .split(':');\n-\n-    return this.validateCredentials(username, password);\n+    try {\n+      const decoded = jwt.verify(token, this.config.jwt_secret) as JwtPayload;\n+      \n+      if (!decoded.sub || !decoded.exp) {\n+        throw new Error('Invalid token structure');\n+      }\n+      \n+      if (decoded.exp < Date.now() / 1000) {\n+        throw new Error('Token has expired');\n+      }\n+      \n+      const user = await this.userService.findById(decoded.sub);\n+      if (!user) {\n+        throw new Error('User not found');\n+      }\n+      \n+      if (!user.active) {\n+        throw new Error('User account is disabled');\n+      }\n+      \n+      return user;\n+    } catch (error) {\n+      throw new AuthenticationError('Invalid or expired token');\n+    }\n   }",
        "status": "modified"
      },
      {
        "additions": 50,
        "changes": 50,
        "deletions": 0,
        "filename": "tests/auth.test.ts",
        "patch": "@@ -0,0 +1,50 @@\n+import { describe, it, expect, jest } from 'jest';\n+import { AuthService } from '../src/services/auth';\n+import { UserService } from '../src/services/user';\n+import { AuthenticationError } from '../src/errors';\n+\n+describe('AuthService', () => {\n+  let authService: AuthService;\n+  let userService: jest.Mocked<UserService>;\n+\n+  beforeEach(() => {\n+    userService = {\n+      findById: jest.fn(),\n+    } as any;\n+\n+    authService = new AuthService({\n+      jwt_secret: 'test-secret',\n+      token_expiry: '1h'\n+    }, userService);\n+  });\n+\n+  describe('validateToken', () => {\n+    it('should successfully validate a valid token', async () => {\n+      const mockUser = {\n+        id: '123',\n+        active: true,\n+        name: 'Test User'\n+      };\n+\n+      userService.findById.mockResolvedValue(mockUser);\n+\n+      const token = authService.generateToken(mockUser);\n+      const result = await authService.validateToken(token);\n+\n+      expect(result).toEqual(mockUser);\n+      expect(userService.findById).toHaveBeenCalledWith('123');\n+    });\n+\n+    it('should throw on expired token', async () => {\n+      const mockUser = {\n+        id: '123',\n+        active: true,\n+        name: 'Test User'\n+      };\n+\n+      // Generate token that's already expired\n+      const token = authService.generateToken(mockUser, '-1h');\n+\n+      await expect(authService.validateToken(token))\n+        .rejects\n+        .toThrow(AuthenticationError);\n+    });\n+  });\n+});",
        "status": "added"
      },
      {
        "additions": 15,
        "changes": 20,
        "deletions": 5,
        "filename": "README.md",
        "patch": "@@ -10,8 +10,18 @@ ## Authentication\n-### Basic Authentication\n-To authenticate requests, provide your credentials in the Authorization header:\n-\n-```\n-Authorization: Basic base64(username:password)\n-```\n+### OAuth2 Authentication\n+\n+This API uses OAuth2 for authentication. To authenticate requests, include a Bearer token in the Authorization header:\n+\n+```\n+Authorization: Bearer <your_token>\n+```\n+\n+#### Obtaining a Token\n+\n+1. Redirect users to `/oauth/authorize`\n+2. Users approve the application\n+3. Exchange the authorization code for a token at `/oauth/token`\n+\n+Tokens expire after 1 hour. Use the refresh token to obtain a new access token.\n+\n+For more details, see our [OAuth2 Implementation Guide](./docs/oauth2.md).",
        "status": "modified"
      }
    ],
    "commit_message": "feat: implement OAuth2 authentication",
    "commit_sha": "abc123def456789ghijklmnop",
    "files_changed": [
      "src/services/auth.ts",
      "tests/auth.test.ts",
      "README.md"
    ],
    "new_comment": {
      "author": "security-expert",
      "body": "We should consider adding rate limiting here to prevent brute force attacks on the token validation.",
      "created_at": "2024-03-21T16:20:00Z",
      "diff_hunk": "@@ -15,10 +15,25 @@ export class AuthService {\n   private async validateToken(token: string) {\n+    try {\n+      const decoded = jwt.verify(token, this.config.jwt_secret) as JwtPayload;",
      "filename": "src/services/auth.ts",
      "id": 777888999,
      "line": 17,
      "node_id": "PRRC_kwDOA5555555555",
      "original_line": 2,
      "original_position": 2,
      "original_start_line": 16,
      "start_line": 16,
      "start_side": "RIGHT",
      "subject_type": "line",
      "url": "https://api.github.com/repos/octocat/Hello-World/pulls/123/comments/777888999"
    },
    "owner": "octocat",
    "pull_request": {
      "author": "developer123",
      "body": "This PR adds OAuth2 authentication support and removes the basic auth implementation.\n\nChanges:\n- Replaces basic auth with JWT-based OAuth2\n- Adds comprehensive tests\n- Updates documentation\n- Adds token validation and expiry handling\n\nPlease review the token expiry duration and error messages.",
      "comments": [
        {
          "author": "reviewer456",
          "body": "Could you add some documentation about token refresh flows? Particularly around handling expired refresh tokens.",
          "created_at": "2024-03-21T11:30:00Z",
          "diff_hunk": "@@ -15,7 +15,12 @@ export class AuthService {\n   private async validateToken(token: string) {\n-    // Basic auth validation\n-    const [username, password] = Buffer.from(token, 'base64')\n-      .toString()\n-      .split(':');\n-\n-    return this.validateCredentials(username, password);\n+    try {\n+      const decoded = jwt.verify(token, this.config.jwt_secret) as JwtPayload;",
          "filename": "src/services/auth.ts",
          "id": 444555666,
          "line": 17,
          "node_id": "PRRC_kwDOA3333333333",
          "original_line": 2,
          "original_position": 2,
          "original_start_line": 15,
          "start_line": 17,
          "start_side": "RIGHT",
          "subject_type": "line",
          "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/444555666"
        },
        {
          "author": "security-reviewer",
          "body": "We should add a check for token blacklisting here in case we need to revoke access.",
          "created_at": "2024-03-21T12:15:00Z",
          "diff_hunk": "@@ -20,6 +20,11 @@ export class AuthService {\n       if (!decoded.sub || !decoded.exp) {\n         throw new Error('Invalid token structure');\n       }\n+      \n+      if (decoded.exp < Date.now() / 1000) {\n+        throw new Error('Token has expired');\n+      }\n+      \n+      const user = await this.userService.findById(decoded.sub);",
          "filename": "src/services/auth.ts",
          "id": 444555667,
          "line": 25,
          "node_id": "PRRC_kwDOA3333333334",
          "original_line": null,
          "original_position": 5,
          "original_start_line": null,
          "start_line": 25,
          "start_side": "RIGHT",
          "subject_type": "line",
          "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/444555667"
        },
        {
          "author": "developer123",
          "body": "Good catch! I'll add the blacklist check in the next commit.",
          "created_at": "2024-03-21T12:30:00Z",
          "diff_hunk": "@@ -25,6 +25,10 @@ export class AuthService {\n       if (decoded.exp < Date.now() / 1000) {\n         throw new Error('Token has expired');\n       }\n+      \n+      const user = await this.userService.findById(decoded.sub);\n+      if (!user) {\n+        throw new Error('User not found');\n+      }",
          "filename": "src/services/auth.ts",
          "id": 444555668,
          "line": 28,
          "node_id": "PRRC_kwDOA3333333335",
          "original_line": null,
          "original_position": 8,
          "original_start_line": null,
          "start_line": 28,
          "start_side": "RIGHT",
          "subject_type": "line",
          "url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/444555668"
        }
      ],
      "created_at": "2024-03-21T10:00:00Z",
      "id": 987654321,
      "labels": [
        {
          "color": "84b6eb",
          "default": true,
          "description": "New feature or request",
          "id": 111222,
          "name": "enhancement",
          "node_id": "LA_kwDOA1111111111"
        },
        {
          "color": "d93f0b",
          "default": false,
          "description": "Security related changes",
          "id": 333444,
          "name": "security",
          "node_id": "LA_kwDOA2222222222"
        }
      ],
      "node_id": "PR_kwDOA1234567890",
      "number": 123,
      "state": "open",
      "title": "Implement OAuth2 Authentication",
      "url": "https://api.github.com/repos/octocat/Hello-World/pulls/123"
    },
    "ref": "feature/oauth-auth",
    "repo": "Hello-World"
  }
  ````

  ```python agent.py theme={null}
  def agent(input):
      $raw = input.get("$raw")
      action = input.get("action")
      author = input.get("author")
      changes = input.get("changes")
      commit_message = input.get("commit_message")
      commit_sha = input.get("commit_sha")
      files_changed = input.get("files_changed")
      new_comment = input.get("new_comment")
      owner = input.get("owner")
      pull_request = input.get("pull_request")
      ref = input.get("ref")
      repo = input.get("repo")
  ```
</CodeGroup>

## Fields

<ResponseField name="$raw" type="object">
  The raw Github `pull_request_review_comment` event payload.
</ResponseField>

<ResponseField name="action" type="string">
  The action that occurred on the pull request.

  <Expandable title="action values">
    <ResponseField name="opened" type="string">
      The pull request was opened.
    </ResponseField>

    <ResponseField name="edited" type="string">
      The pull request was edited. For example, the title or description was changed.
    </ResponseField>

    <ResponseField name="synchronize" type="string">
      The pull request was synchronized. For example, when a new commit is pushed to the branch.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="author" type="string">
  The author of the pull request.
</ResponseField>

<ResponseField name="changes" type="change[]">
  The changes that were made to the files in the pull request.

  <Expandable title="change properties">
    <ResponseField name="additions" type="number">
      The number of additions in the change.
    </ResponseField>

    <ResponseField name="changes" type="number">
      The number of changes in the change.
    </ResponseField>

    <ResponseField name="deletions" type="number">
      The number of deletions in the change.
    </ResponseField>

    <ResponseField name="filename" type="string">
      The filename of the changed file.
    </ResponseField>

    <ResponseField name="patch" type="string">
      The patch (or code) of the change.
    </ResponseField>

    <ResponseField name="status" type="string">
      The status of the change.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="commit_message" type="string">
  The commit message of the pull request.
</ResponseField>

<ResponseField name="commit_sha" type="string">
  The SHA of the commit that was used to create the pull request.
</ResponseField>

<ResponseField name="files_changed" type="string[]">
  The filepaths that were changed in the pull request.
</ResponseField>

<ResponseField name="new_comment" type="object">
  The new comment that was added to the pull request.

  <Expandable title="new_comment properties">
    <ResponseField name="author" type="string">
      The author of the comment.
    </ResponseField>

    <ResponseField name="body" type="string">
      The body of the comment.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      The date and time the comment was created.
    </ResponseField>

    <ResponseField name="diff_hunk" type="string">
      The diff hunk of the comment.
    </ResponseField>

    <ResponseField name="filename" type="string">
      The filename of the file that the comment was added to.
    </ResponseField>

    <ResponseField name="id" type="number">
      The ID of the comment.
    </ResponseField>

    <ResponseField name="node_id" type="string">
      The node ID of the comment.
    </ResponseField>

    <ResponseField name="original_line" type="number">
      The original line number of the comment.
    </ResponseField>

    <ResponseField name="original_position" type="number">
      The original position of the comment.
    </ResponseField>

    <ResponseField name="original_start_line" type="number">
      The original start line of the comment.
    </ResponseField>

    <ResponseField name="start_line" type="number">
      The start line of the comment.
    </ResponseField>

    <ResponseField name="start_side" type="string">
      The start side of the comment.
    </ResponseField>

    <ResponseField name="subject_type" type="string">
      The subject type of the comment.
    </ResponseField>

    <ResponseField name="url" type="string">
      The URL of the comment.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="owner" type="string">
  The owner of the repository.
</ResponseField>

<ReponseField name="pull_request" type="object">
  The pull request that the comment occurred on.

  <Expandable title="pull_request properties">
    <ResponseField name="author" type="string">
      The author of the pull request.
    </ResponseField>

    <ResponseField name="body" type="string">
      The body of the pull request.
    </ResponseField>

    <ResponseField name="comments" type="object[]">
      The comments on the pull request.

      <Expandable title="comment properties">
        <ResponseField name="author" type="string">
          The author of the comment.
        </ResponseField>

        <ResponseField name="body" type="string">
          The body of the comment.
        </ResponseField>

        <ResponseField name="created_at" type="string">
          The date and time the comment was created.
        </ResponseField>

        <ResponseField name="diff_hunk" type="string">
          The diff hunk of the comment.
        </ResponseField>

        <ResponseField name="filename" type="string">
          The filename of the file that the comment was added to.
        </ResponseField>

        <ResponseField name="id" type="number">
          The ID of the comment.
        </ResponseField>

        <ResponseField name="node_id" type="string">
          The node ID of the comment.
        </ResponseField>

        <ResponseField name="original_line" type="number">
          The original line number of the comment.
        </ResponseField>

        <ResponseField name="original_position" type="number">
          The original position of the comment.
        </ResponseField>

        <ResponseField name="original_start_line" type="number">
          The original start line of the comment.
        </ResponseField>

        <ResponseField name="start_line" type="number">
          The start line of the comment.
        </ResponseField>

        <ResponseField name="start_side" type="string">
          The start side of the comment.
        </ResponseField>

        <ResponseField name="subject_type" type="string">
          The subject type of the comment.
        </ResponseField>

        <ResponseField name="url" type="string">
          The URL of the comment.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="created_at" type="string">
      The date and time the pull request was created.
    </ResponseField>

    <ResponseField name="id" type="number">
      The ID of the pull request.
    </ResponseField>

    <ResponseField name="labels" type="object[]">
      The labels on the pull request.

      <Expandable title="label properties">
        <ResponseField name="color" type="string">
          The color of the label.
        </ResponseField>

        <ResponseField name="default" type="boolean">
          Whether the label is the default label.
        </ResponseField>

        <ResponseField name="description" type="string">
          The description of the label.
        </ResponseField>

        <ResponseField name="id" type="number">
          The ID of the label.
        </ResponseField>

        <ResponseField name="name" type="string">
          The name of the label.
        </ResponseField>

        <ResponseField name="node_id" type="string">
          The node ID of the label.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="node_id" type="string">
      The node ID of the pull request.
    </ResponseField>

    <ResponseField name="number" type="number">
      The number of the pull request.
    </ResponseField>

    <ResponseField name="state" type="string">
      The state of the pull request.
    </ResponseField>

    <ResponseField name="title" type="string">
      The title of the pull request.
    </ResponseField>

    <ResponseField name="url" type="string">
      The URL of the pull request.
    </ResponseField>
  </Expandable>
</ReponseField>

<ResponseField name="ref" type="string">
  The ref of the pull request.
</ResponseField>

<ResponseField name="repo" type="string">
  The repository of the pull request.
</ResponseField>
