Skip to content

Commit

Permalink
fix: adds serialized comment object and payload to the schema
Browse files Browse the repository at this point in the history
  • Loading branch information
sshivaditya committed Sep 11, 2024
1 parent 1549feb commit 71854b4
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .github/.ubiquibot-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
plugins:
- name: test-app
id: test-app
uses:
- plugin: https://ubiquity-os-comment-vector-embeddings.sshivaditya.workers.dev
runsOn: [ "issue_comment.created", "issue_comment.edited", "issue_comment.deleted" ]
2 changes: 1 addition & 1 deletion .github/workflows/compute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
VOYAGE_API_KEY: ${{secrets.VOYAGE_API_KEY}}
VOYAGEAI_API_KEY: ${{secrets.VOYAGEAI_API_KEY}}

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To set up the `.dev.vars` file, you will need to provide the following variables
- `SUPABASE_URL`: The URL for your Supabase instance.
- `SUPABASE_KEY`: The key for your Supabase instance.
- `OPENAI_API_KEY`: The API key for OpenAI.
- `VOYAGE_API_KEY`: The API key for Voyage.
- `VOYAGEAI_API_KEY`: The API key for Voyage.

## Usage
- Add the following to your `.ubiquibot-config.yml` file with the appropriate URL:
Expand Down
13 changes: 9 additions & 4 deletions src/adapters/supabase/helpers/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class Comment extends SuperSupabase {
super(supabase, context);
}

async createComment(plaintext: string | null, commentNodeId: string, authorId: number, isPrivate: boolean) {
async createComment(plaintext: string | null, commentNodeId: string, authorId: number, commentobject: JSON | null, isPrivate: boolean) {
//First Check if the comment already exists
const { data, error } = await this.supabase.from("issue_comments").select("*").eq("id", commentNodeId);
if (error) {
Expand All @@ -36,7 +36,9 @@ export class Comment extends SuperSupabase {
if (isPrivate) {
plaintext = null as string | null;
}
const { error } = await this.supabase.from("issue_comments").insert([{ id: commentNodeId, plaintext, author_id: authorId, embedding: embedding }]);
const { error } = await this.supabase
.from("issue_comments")
.insert([{ id: commentNodeId, plaintext, author_id: authorId, commentobject, embedding: embedding }]);
if (error) {
this.context.logger.error("Error creating comment", error);
return;
Expand All @@ -45,7 +47,7 @@ export class Comment extends SuperSupabase {
this.context.logger.info("Comment created successfully");
}

async updateComment(plaintext: string | null, commentNodeId: string, isPrivate: boolean) {
async updateComment(plaintext: string | null, commentNodeId: string, commentobject: JSON, isPrivate: boolean) {
//Create the embedding for this comment
const embedding = Array.from(await this.context.adapters.voyage.embedding.createEmbedding(plaintext));
if (embedding.length < 3072) {
Expand All @@ -54,7 +56,10 @@ export class Comment extends SuperSupabase {
if (isPrivate) {
plaintext = null as string | null;
}
const { error } = await this.supabase.from("issue_comments").update({ plaintext, embedding: embedding, modified_at: new Date() }).eq("id", commentNodeId);
const { error } = await this.supabase
.from("issue_comments")
.update({ plaintext, embedding: embedding, commentobject, modified_at: new Date() })
.eq("id", commentNodeId);
if (error) {
this.context.logger.error("Error updating comment", error);
}
Expand Down
37 changes: 37 additions & 0 deletions src/adapters/utils/cleancommentobject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { EmitterWebhookEvent as WebhookEvent } from "@octokit/webhooks";
import { Type } from "@sinclair/typebox";

const commentObjectSchema = Type.Object({
action: Type.String(),
issue: Type.Object({
id: Type.Number(),
number: Type.Number(),
title: Type.String(),
body: Type.String(),
user: Type.Object({
login: Type.String(),
id: Type.Number(),
}),
}),
comment: Type.Object({
author_association: Type.String(),
id: Type.Number(),
html_url: Type.String(),
issue_url: Type.String(),
user: Type.Object({
login: Type.String(),
id: Type.Number(),
}),
}),
});

/**
* Cleans the comment object.
*
* @param commentObject - The comment object.
* @returns The cleaned comment object.
*/
export const cleanCommentObject = (commentObject: WebhookEvent["payload"]): JSON => {
// Apply the schema to the comment object
return commentObjectSchema.parse(commentObject);
};
4 changes: 3 additions & 1 deletion src/handlers/add-comments.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cleanCommentObject } from "../adapters/utils/cleancommentobject";
import { Context } from "../types";

export async function addComments(context: Context) {
Expand All @@ -6,14 +7,15 @@ export async function addComments(context: Context) {
payload,
adapters: { supabase },
} = context;
const commentobject = cleanCommentObject(payload);
const plaintext = payload.comment.body;
const authorId = payload.comment.user?.id || -1;
const nodeId = payload.comment.node_id;
const isPrivate = payload.repository.private;

// Add the comment to the database
try {
await supabase.comment.createComment(plaintext, nodeId, authorId, isPrivate);
await supabase.comment.createComment(plaintext, nodeId, authorId, commentobject as JSON, isPrivate);
} catch (error) {
if (error instanceof Error) {
logger.error(`Error creating comment:`, { error: error, stack: error.stack });
Expand Down
5 changes: 3 additions & 2 deletions src/handlers/update-comments.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cleanCommentObject } from "../adapters/utils/cleancommentobject";
import { Context } from "../types";

export async function updateComment(context: Context) {
Expand All @@ -6,13 +7,13 @@ export async function updateComment(context: Context) {
payload,
adapters: { supabase },
} = context;

const commentobject = cleanCommentObject(payload);
const nodeId = payload.comment.node_id;
const isPrivate = payload.repository.private;
const plaintext = payload.comment.body;
// Fetch the previous comment and update it in the db
try {
await supabase.comment.updateComment(plaintext, nodeId, isPrivate);
await supabase.comment.updateComment(plaintext, nodeId, commentobject, isPrivate);
} catch (error) {
if (error instanceof Error) {
logger.error(`Error updating comment:`, { error: error, stack: error.stack });
Expand Down
2 changes: 1 addition & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export async function plugin(inputs: PluginInputs, env: Env) {
apiKey: env.OPENAI_API_KEY,
});
const voyageClient = new VoyageAIClient({
apiKey: env.VOYAGE_API_KEY,
apiKey: env.VOYAGEAI_API_KEY,
});
const context: Context = {
eventName: inputs.eventName,
Expand Down
2 changes: 1 addition & 1 deletion src/types/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const envSchema = T.Object({
SUPABASE_URL: T.String(),
SUPABASE_KEY: T.String(),
OPENAI_API_KEY: T.String(),
VOYAGE_API_KEY: T.String(),
VOYAGEAI_API_KEY: T.String(),
});

export const envValidator = new StandardValidator(envSchema);
Expand Down
2 changes: 2 additions & 0 deletions supabase/migrations/20240911023641_issue_comments.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE issue_comments
ADD COLUMN commentobject jsonb;
12 changes: 8 additions & 4 deletions tests/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Logs } from "@ubiquity-dao/ubiquibot-logger";
import { Env } from "../src/types";
import { runPlugin } from "../src/plugin";
import { CommentMock, createMockAdapters } from "./__mocks__/adapter";
import { cleanCommentObject } from "../src/adapters/utils/cleancommentobject";

dotenv.config();
jest.requireActual("@octokit/rest");
Expand Down Expand Up @@ -42,7 +43,7 @@ describe("Plugin tests", () => {
SUPABASE_KEY: "test",
SUPABASE_URL: "test",
OPENAI_API_KEY: "test",
VOYAGE_API_KEY: "test",
VOYAGEAI_API_KEY: "test",
});
const content = await response.json();
expect(content).toEqual(manifest);
Expand All @@ -52,8 +53,9 @@ describe("Plugin tests", () => {
const { context } = createContext(STRINGS.HELLO_WORLD, 1, 1, 1, 1, "sasasCreate");
await runPlugin(context);
const supabase = context.adapters.supabase;
const commentObject = cleanCommentObject(context.payload);
try {
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasCreate", 1, false);
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasCreate", 1, commentObject, false);
throw new Error("Expected method to reject.");
} catch (error) {
if (error instanceof Error) {
Expand All @@ -69,7 +71,8 @@ describe("Plugin tests", () => {
it("When a comment is updated it should update the database", async () => {
const { context } = createContext("Updated Message", 1, 1, 1, 1, "sasasUpdate", "issue_comment.edited");
const supabase = context.adapters.supabase;
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasUpdate", 1, false);
const commentObject = cleanCommentObject(context.payload);
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasUpdate", 1, commentObject, false);
await runPlugin(context);
const comment = (await supabase.comment.getComment("sasasUpdate")) as unknown as CommentMock;
expect(comment).toBeDefined();
Expand All @@ -80,7 +83,8 @@ describe("Plugin tests", () => {
it("When a comment is deleted it should delete it from the database", async () => {
const { context } = createContext("Text Message", 1, 1, 1, 1, "sasasDelete", "issue_comment.deleted");
const supabase = context.adapters.supabase;
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasDelete", 1, false);
const commentObject = cleanCommentObject(context.payload);
await supabase.comment.createComment(STRINGS.HELLO_WORLD, "sasasDelete", 1, commentObject, false);
await runPlugin(context);
try {
await supabase.comment.getComment("sasasDelete");
Expand Down

0 comments on commit 71854b4

Please sign in to comment.