10000 feat: Connect conversations to GitHub issues (#12) by vikaswakde · Pull Request #47 · antiwork/helper · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: Connect conversations to GitHub issues (#12) #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Mar 18, 2025

Conversation

vikaswakde
Copy link
Contributor
@vikaswakde vikaswakde commented Mar 9, 2025

Implements GitHub integration for Helper, allowing users to:


  • Connect GitHub accounts to mailboxes
  • Select repositories for issue tracking
helperai-github-integration-demo.mov

  • Create GitHub issues from conversations
Screen.Recording.1403-12-25.at.8.31.53.PM.mov

  • Link existing GitHub issues to conversations
Screen.Recording.1403-12-25.at.8.35.29.PM.mov

  • Synchronize issue states between Helper and GitHub
Screen.Recording.1403-12-25.at.9.17.54.PM.mov

This integration enables teams to track support requests and bugs directly
from Helper conversations, with bidirectional synchronization ensuring
that issue status is always up-to-date in both systems.

Closes #12

conversationSummary?: string | string[] | null;
}

// Define the GitHub issue type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of the comments in this PR are unnecessary, the code reads well on its own

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will cleanup the comments

updatedAt: string;
}

export const GitHubIssueButton = ({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please integrate this into the command bar instead, we're trying to avoid adding buttons. Ideally the form should work similarly to "add note" / tool execution

Screenshot 2025-03-09 at 21 54 12

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the button to now be in 'command bar' instead of in conversation tabs.

checkout this commit : 7a2b578

screenshot :
Screenshot 1403-12-20 at 9 08 49 AM

const [selectedIssueNumber, setSelectedIssueNumber] = useState<number | null>(null);

// Get conversation details to check if a GitHub issue is already linked
const { data: conversation, refetch: refetchConversation } = api.mailbox.conversations.get.useQuery(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be a bit nicer to use useConversationContext

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this fixes redundancy : 3d6ba2d

Comment on lines 491 to 496
<>
<span className="inline-flex items-center rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground mr-1">
Closed
</span>
<HumanizedTime time={conversation.closedAt ?? conversation.updatedAt} titlePrefix="Closed on" />
</>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look related?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed at : 2913a77

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still a diff (adding the fragment), please check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplified : 40bc1bc

try {
setIsLoading(true);
setRepositories(
await utils.client.mailbox.github.repositories.query({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useQuery should simplify the state handling here (or let me know if there's a reason you're not using it!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried using it, but then it bombarded with so much errors for onError so went with this option


return {
accessToken: data.access_token,
username: userResponse.data.login,
Copy link
Collaborator
@binary-koan binary-koan Mar 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we save the username?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently not any particular reason for it, but just for identification and displays purposes, that being said, its absolutely not essential part of core functionality.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep things simple and remove it until we need it then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplified it : 052aaba

Copy link
Collaborator
@binary-koan binary-koan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vikaswakde _a Thanks for the PR, the functionality looks great! I've added some initial comments (in 2 reviews because I mis-clicked ...), could you take a look?

Apologies some of these weren't clear, we haven't had a chance to document things in detail yet

Comment on lines 126 to 127
console.error("Error listing repository issues:", error);
throw new Error("Failed to list issues for this repository");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I think we can let things like this fail rather than having custom error handlers (if it's for the message, we should throw a tRPC error class in the procedure)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: 2e889c3

import { createGitHubIssue, getGitHubIssue, listRepositoryIssues, updateGitHubIssueState } from "@/lib/github/client";
import { mailboxProcedure } from "./procedure";

export const githubConversationsRouter = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we nest this under conversations and use conversationProcedure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nested it under conversations and used conversationProcedure : aea30d7


if (mailbox?.githubAccessToken) {
// Map conversation status to GitHub issue state
const githubState = updatedConversation.status === "closed" ? "closed" : "open";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should do this, "closed" for the conversation just means we've replied, not that the issue is fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then should we only allow 'closing' of an issue from GitHub repo and not from our connect to github UI ?

in current code, I had added this close issue button to close issues
Screenshot 1403-12-21 at 11 56 24 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, missed this - let's keep this simple and remove the button

Copy link
Collaborator
@binary-koan binary-koan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(misclick again, I need coffee ...)

Copy link
Collaborator
@binary-koan binary-koan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vikaswakde Added a few more comments; could you also check my last two above? Otherwise this is looking good!

Mind listing (or screenshotting) what permissions the GH app needs so I can test it?

Comment on lines 37 to 39
const [isCreating, setIsCreating] = useState(false);
const [isLinking, setIsLinking] = useState(false);
const [isUpdatingState, setIsUpdatingState] = useState(false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just use isPending from useMutation for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplified : d0a71f0

) : issues && issues.length > 0 ? (
<div className="space-y-2">
<Label htmlFor="issue">Select an issue</Label>
<Select
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should ideally be a combobox which searches issues matching the filter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great suggestion I updated the simple selector with more ux friendly combobox : 9749f22

@@ -120,7 +126,7 @@ export function TicketCommandBar({
}
break;
case "ArrowLeft":
if (page === "previous-replies" || page === "assignees") {
if (page === "previous-replies" || page === "assignees" || page === "github-issue") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think these are needed since the github-issue page doesn't use the command component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 51 to 62
const { data: issues, isLoading: isLoadingIssues } = (api.mailbox.conversations as any).listRepositoryIssues.useQuery(
{
state: "open",
mailboxSlug,
},
{
enabled: activeTab === "link",
staleTime: 30000,
},
);

const conversationWithGitHub = conversation as any;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These shouldn't need as any if tRPC is working correctly


return {
accessToken: data.access_token,
username: userResponse.data.login,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep things simple and remove it until we need it then

console.log(`Updated conversation ${conversation.id} status to closed`);

// Add a message to the conversation that the issue was closed
await db.insert(conversationMessages).values({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what we should do here is

  • Use createReply to send a friendly message to the customer (ideally configurable in settings, but could just be hardcoded to something like "Hi, our team has resolved the issue so this should work now. Please let us know if you continue having problems.")
  • Add the message you have here as a note using addNote - notes can use markdown IIRC so would be nice to link to the issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this look : 93bf858

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Don't think we need the logs, we can tell if it worked from whether the db records are created

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure cleaned up: 9567907

@@ -120,6 +126,38 @@ export const disconnectSlack = async (mailboxId: number): Promise<void> => {
.where(eq(mailboxes.id, mailboxId));
};

export const disconnectGitHub = async (mailboxId: number): Promise<void> => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should (can) we also make an API call to disconnect the app in GitHub?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made it : d6ffcb4

}

return (
<DialogContent className="sm:max-w-[600px]">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DialogContent wrapper looks awkward here, could you please update the design to be closer to the note/tool pages?

Screenshot 2025-03-11 at 11 04 45

Copy link
Contributor Author
@vikaswakde vikaswakde Mar 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this more simplified version: should I commit it ? or do you have any design in mind?

Screenshot 1403-12-22 at 9 39 34 PM

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that looks good!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed how the command bar displays; if you commit that I'm happy to deal with the conflicts and get it working with the new design

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds great : 74f54c9

@vikaswakde
Copy link
Contributor Author

@binary-koan here is the gist where I explain the steps needed to connect and use GitHub with helper :
https://gist.github.com/vikaswakde/e2f84128d05adf678eb667a6fcd9f569

@binary-koan
Copy link
Collaborator

(will look at this properly again tomorrow, sorry for the delay!)

@binary-koan
Copy link
Collaborator

@vikaswakde I merged main and did a couple more tweaks here: #52. Could you please merge that in?

Also, when I try to create an issue after connecting my GH account in settings I get this error, even though I've added the Read & write Issues permission in our GitHub app settings. I think the app is maybe authorized but not installed? Could you check if the flow is requesting the right permissions?

Error [TRPCError]: Resource not accessible by integration - https://docs.github.com/rest/issues/issues#create-an-issue

And could you please update the demo videos above to show the latest design so we can get Sahil's input on the UX?

@vikaswakde
Copy link
Contributor Author

@vikaswakde I merged main and did a couple more tweaks here: #52. Could you please merge that in?

Also, when I try to create an issue after connecting my GH account in settings I get this error, even though I've added the Read & write Issues permission in our GitHub app settings. I think the app is maybe authorized but not installed? Could you check if the flow is requesting the right permissions?

Error [TRPCError]: Resource not accessible by integration - https://docs.github.com/rest/issues/issues#create-an-issue

And could you please update the demo videos above to show the latest design so we can get Sahil's input on the UX?

@binary-koan hello, I tried to recreate the issue but I was not able to get the similar issue,

I checkout to /github-integration-fix #52 branch , and I was able to create a new issue without any error!

steps I followed:


  1. create a new app from this url : https://github.com/settings/applications/new

Values I entered for creating that app :

Homepage URL > https://helperai.dev

Callback URL > https://helperai.dev/api/connect/github/callback

Screenshot 1403-12-25 at 6 56 19 PM
2) get `client id` and `client secret` and update `local.env`

Screenshot 1403-12-25 at 7 05 55 PM (creds have be revoked)
  1. connect GitHub in helper settings
Screenshot 1403-12-25 at 7 10 15 PM




  1. select the repo which I want to create issues in and click update settings

  2. then visited that repos settings and checked issues tab

Screenshot 1403-12-25 at 7 13 59 PM Screenshot 1403-12-25 at 7 16 00 PM
  1. and then I was able to create a new issue
Screenshot 1403-12-25 at 6 44 09 PM

@binary-koan
Copy link
Collaborator

@slavingia Any feedback on the UX? (see videos in the description)

Apart from working through the permissions issue I'm seeing this is good to go from my side

@slavingia
Copy link
Collaborator

Looks good! Maybe the color of the GitHub icon should change upon hover, as you can't see it.

@vikaswakde
Copy link
Contributor Author
Screen.Recording.1403-12-25.at.10.09.57.PM.mov

@vikaswakde
Copy link
Contributor Author

@binary-koan how to fix this .json file conflicts?

@binary-koan
Copy link
Collaborator

@vikaswakde Easiest to recreate the migration:

  • Delete the migration and snapshot and reset _journal.json to main
  • npm run db:generate
  • npm run db:reset

Looks like main has an 0061 migration, so those steps should create an 0062 migration with your changes. LMK if you run into problems!

(IIRC Drizzle is planning to release a better migration tool soonish which should have a less hacky way to do it)

@vikaswakde
Copy link
Contributor Author

@vikaswakde Easiest to recreate the migration:

  • Delete the migration and snapshot and reset _journal.json to main
  • npm run db:generate
  • npm run db:reset

Looks like main has an 0061 migration, so those steps should create an 0062 migration with your changes. LMK if you run into problems!

(IIRC Drizzle is planning to release a better migration tool soonish which should have a less hacky way to do it)

so, if I could do this successfully, then should I merge main into my branch ? or what I need to do now ?

@binary-koan
Copy link
Collaborator

Yeah sorry, I mean merge main after deleting the files and before running db:generate

Once conflicts are solved we can merge this and I'll work on a small follow-up to fix the permissions issue (since I can reproduce it with our app)

vikaswakde and others added 2 commits March 17, 2025 01:23
@vikaswakde
Copy link
Contributor Author

Yeah sorry, I mean merge main after deleting the files and before running db:generate

Once conflicts are solved we can merge this and I'll work on a small follow-up to fix the permissions issue (since I can reproduce it with our app)

I merged main into my branch and solved the conflicts that occurred

@binary-koan
Copy link
Collaborator

Thanks! Trying to get it working with our app today (think we need to authenticate as an app instead of via OAuth), will merge once I have that

@binary-koan binary-koan merged commit 6ba976f into antiwork:main Mar 18, 2025
1 of 3 checks passed
binary-koan added a commit that referenced this pull request Mar 18, 2025
Improves #47 so it works with our GitHub app and can be installed on
other orgs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Connect conversation to GitHub
3 participants
0