Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Ask Command #663

Merged
merged 37 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
45a15af
feat(deps): added openai
Keyrxng Aug 23, 2023
bfe3409
feat: added ask command
Keyrxng Aug 23, 2023
9ca0a6b
fix: update prompt
Keyrxng Aug 23, 2023
da4a3f7
fix: update system prompt
Keyrxng Aug 23, 2023
d9cc49b
Merge branch 'ubiquity:development' into ask
Keyrxng Aug 25, 2023
8e6b42b
feat: simple memory
Keyrxng Aug 25, 2023
dd153f4
fix: comments
Keyrxng Aug 25, 2023
5588905
fix: streamlined context
Keyrxng Aug 27, 2023
6d4ff92
chore: pulling context
Keyrxng Aug 31, 2023
6725419
chore: tokenization
Keyrxng Aug 31, 2023
7322a59
chore: diff comparison
Keyrxng Aug 31, 2023
a1343cf
fix: ci and spec check
Keyrxng Sep 4, 2023
d3104df
Merge branch 'development' into ask
Keyrxng Sep 5, 2023
99b8aa2
fix: merge mistake
Keyrxng Sep 5, 2023
4a4d32d
fix: key from config
Keyrxng Sep 5, 2023
8b80e39
fix: set ask to false
Keyrxng Sep 5, 2023
3c669df
fix(deps): langchain
Keyrxng Sep 7, 2023
0dbfde3
Merge branch 'development' into ask
Keyrxng Sep 7, 2023
911952f
fix: apikey undefined
Keyrxng Sep 7, 2023
8cf84b8
fix: using token limit
Keyrxng Sep 7, 2023
d529dd7
Merge branch 'development' into ask
Keyrxng Sep 7, 2023
c7c96aa
chore: improve ask command
Keyrxng Sep 10, 2023
b659fab
Merge branch 'ubiquity:development' into ask
Keyrxng Sep 10, 2023
8d0832a
fix: gpt helpers
Keyrxng Sep 10, 2023
140d7f0
Merge branch 'development' into ask
Keyrxng Sep 10, 2023
27a2091
Merge branch 'development' into ask
Keyrxng Sep 10, 2023
1cc4f39
Merge branch 'development' into ask
Keyrxng Sep 11, 2023
7f0a2e9
Merge branch 'development' into ask
Keyrxng Sep 12, 2023
3eee89f
chore: use error diff
Keyrxng Sep 12, 2023
729bd8a
fix: remove unused
Keyrxng Sep 13, 2023
720d188
fix: remove unused
Keyrxng Sep 14, 2023
877941c
Merge branch 'development' into ask
Keyrxng Sep 14, 2023
a3525f1
fix: schema
Keyrxng Sep 14, 2023
ff9e586
fix: nullable and error
Keyrxng Sep 14, 2023
0cdc99e
Merge branch 'development' into ask
Keyrxng Sep 16, 2023
8c98be3
Merge branch 'development' into pr/663
0xcodercrane Sep 21, 2023
4e1a7b8
fix: duplicated
0xcodercrane Sep 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SUPABASE_KEY=
AUTO_PAY_MODE=
ANALYTICS_MODE=


# Use `trace` to get verbose logging or `info` to show less
LOG_LEVEL=debug
LOGDNA_INGESTION_KEY=
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"node-html-parser": "^6.1.5",
"node-html-to-image": "^3.3.0",
"nodemon": "^2.0.19",
"openai": "^4.2.0",
"parse5": "^7.1.2",
"prettier": "^2.7.1",
"probot": "^12.2.4",
Expand Down
6 changes: 6 additions & 0 deletions src/bindings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
registerWalletWithVerification,
staleBountyTime,
enableAccessControl,
openAIKey,
openAITokenLimit,
} = await getWideConfig(context);

const publicKey = await getScalarKey(process.env.X25519_PRIVATE_KEY);
Expand Down Expand Up @@ -99,6 +101,10 @@ export const loadConfig = async (context: Context): Promise<BotConfig> => {
wallet: {
registerWalletWithVerification: registerWalletWithVerification,
},
ask: {
apiKey: openAIKey,
tokenLimit: openAITokenLimit,
},
accessControl: enableAccessControl,
};

Expand Down
2 changes: 2 additions & 0 deletions src/configs/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export const DEFAULT_DISQUALIFY_TIME = "7 days"; // 7 days
export const DEFAULT_NETWORK_ID = 1; // ethereum
export const DEFAULT_RPC_ENDPOINT = "https://rpc-bot.ubq.fi/v1/mainnet";
export const DEFAULT_PERMIT_BASE_URL = "https://pay.ubq.fi";

export const DEFAULT_TOKEN_LIMIT = 4000;
Keyrxng marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions src/handlers/comment/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum IssueCommentCommands {
PAYOUT = "/payout", // request permit payout
MULTIPLIER = "/multiplier", // set bounty multiplier (for treasury)
QUERY = "/query",
ASK = "/ask", // ask GPT a question
// Access Controls

ALLOW = "/allow",
Expand Down
123 changes: 123 additions & 0 deletions src/handlers/comment/handlers/ask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { getBotContext, getLogger } from "../../../bindings";
import { GPTResponse, Payload, StreamlinedComment, UserType } from "../../../types";
import { getAllIssueComments, getAllLinkedIssuesAndPullsInBody } from "../../../helpers";
import { CreateChatCompletionRequestMessage } from "openai/resources/chat";
import { askGPT, decideContextGPT, sysMsg } from "../../../helpers/gpt";
import { ErrorDiff } from "../../../utils/helpers";

/**
* @param body The question to ask
*/
export const ask = async (body: string) => {
const context = getBotContext();
const logger = getLogger();

const payload = context.payload as Payload;
const sender = payload.sender.login;
const issue = payload.issue;

if (!body) {
return `Please ask a question`;
}

if (!issue) {
return `This command can only be used on issues`;
}

const chatHistory: CreateChatCompletionRequestMessage[] = [];
const streamlined: StreamlinedComment[] = [];
let linkedPRStreamlined: StreamlinedComment[] = [];
let linkedIssueStreamlined: StreamlinedComment[] = [];

const regex = /^\/ask\s(.+)$/;
const matches = body.match(regex);

if (matches) {
const [, body] = matches;

// standard comments
const comments = await getAllIssueComments(issue.number);
// raw so we can grab the <!--- { 'UbiquityAI': 'answer' } ---> tag
const commentsRaw = await getAllIssueComments(issue.number, "raw");

if (!comments) {
logger.info(`Error getting issue comments`);
return ErrorDiff(`Error getting issue comments`);
}

// add the first comment of the issue/pull request
streamlined.push({
login: issue.user.login,
body: issue.body,
});

// add the rest
comments.forEach(async (comment, i) => {
if (comment.user.type == UserType.User || commentsRaw[i].body.includes("<!--- { 'UbiquityAI': 'answer' } --->")) {
streamlined.push({
login: comment.user.login,
body: comment.body,
});
}
});

// returns the conversational context from all linked issues and prs
const links = await getAllLinkedIssuesAndPullsInBody(issue.number);

if (typeof links === "string") {
logger.info(`Error getting linked issues or prs: ${links}`);
} else {
linkedIssueStreamlined = links.linkedIssues;
linkedPRStreamlined = links.linkedPrs;
}

// let Chad deduce what is the most relevant context
const gptDecidedContext = await decideContextGPT(chatHistory, streamlined, linkedPRStreamlined, linkedIssueStreamlined);

if (linkedIssueStreamlined.length == 0 && linkedPRStreamlined.length == 0) {
// No external context to add
chatHistory.push(
{
role: "system",
content: sysMsg,
name: "UbiquityAI",
} as CreateChatCompletionRequestMessage,
{
role: "user",
content: body,
name: sender,
} as CreateChatCompletionRequestMessage
);
} else {
chatHistory.push(
{
role: "system",
content: sysMsg, // provide the answer template
name: "UbiquityAI",
} as CreateChatCompletionRequestMessage,
{
role: "system",
content: "Original Context: " + JSON.stringify(gptDecidedContext), // provide the context
name: "system",
} as CreateChatCompletionRequestMessage,
{
role: "user",
content: "Question: " + JSON.stringify(body), // provide the question
name: "user",
} as CreateChatCompletionRequestMessage
);
}

const gptResponse: GPTResponse | string = await askGPT(body, chatHistory);

if (typeof gptResponse === "string") {
return gptResponse;
} else if (gptResponse.answer) {
return gptResponse.answer;
} else {
return ErrorDiff(`Error getting response from GPT`);
}
} else {
return "Invalid syntax for ask \n usage: '/ask What is pi?";
}
};
8 changes: 8 additions & 0 deletions src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { listAvailableCommands } from "./help";
import { unassign } from "./unassign";
import { registerWallet } from "./wallet";
import { setAccess } from "./allow";
import { ask } from "./ask";
import { multiplier } from "./multiplier";
import { BigNumber, ethers } from "ethers";
import { addPenalty } from "../../../adapters/supabase";
Expand Down Expand Up @@ -36,6 +37,7 @@ export * from "./payout";
export * from "./help";
export * from "./multiplier";
export * from "./query";
export * from "./ask";

/**
* Parses the comment body and figure out the command name a user wants
Expand Down Expand Up @@ -251,6 +253,12 @@ export const userCommands = (): UserCommands[] => {
handler: query,
callback: commandCallback,
},
{
id: IssueCommentCommands.ASK,
description: `Ask a technical question to the Ubiquity AI. \n example usage: "/ask How do I do X?"`,
handler: ask,
callback: commandCallback,
},
{
id: IssueCommentCommands.MULTIPLIER,
description: `Set the bounty payout multiplier for a specific contributor, and provide the reason for why. \n example usage: "/wallet @user 0.5 'Multiplier reason'"`,
Expand Down
Loading