From 3e939d5f1600c7e15038c9bbcdcdd4f7206319a0 Mon Sep 17 00:00:00 2001 From: whilefoo Date: Sat, 4 Nov 2023 20:41:36 +0100 Subject: [PATCH] fix: circular dependencies --- src/adapters/index.ts | 4 +- src/adapters/supabase/helpers/tables/logs.ts | 12 +- src/bindings/env.ts | 2 +- src/bindings/event.ts | 15 +- .../handlers/issue/calculate-quality-score.ts | 7 +- src/types/configuration-types.ts | 221 +++++------------- src/utils/ajv.ts | 1 + 7 files changed, 81 insertions(+), 181 deletions(-) diff --git a/src/adapters/index.ts b/src/adapters/index.ts index cbc569354..53029bc22 100644 --- a/src/adapters/index.ts +++ b/src/adapters/index.ts @@ -10,6 +10,7 @@ import { User } from "./supabase/helpers/tables/user"; import { Wallet } from "./supabase/helpers/tables/wallet"; import { Database } from "./supabase/types"; import { env } from "../bindings/env"; +import OpenAI from "openai"; const supabaseClient = createClient(env.SUPABASE_URL, env.SUPABASE_KEY, { auth: { persistSession: false } }); @@ -22,9 +23,10 @@ export function createAdapters(context: Context) { debit: new Settlement(supabaseClient, context), settlement: new Settlement(supabaseClient, context), label: new Label(supabaseClient, context), - logs: new Logs(supabaseClient, context), + logs: new Logs(supabaseClient, context, env.LOG_ENVIRONMENT, env.LOG_RETRY_LIMIT, env.LOG_LEVEL), locations: new Locations(supabaseClient, context), super: new Super(supabaseClient, context), }, + openAi: context.config.keys.openAi ? new OpenAI({ apiKey: context.config.keys.openAi }) : null, }; } diff --git a/src/adapters/supabase/helpers/tables/logs.ts b/src/adapters/supabase/helpers/tables/logs.ts index 9a7b3dc7e..1f0e0dd46 100644 --- a/src/adapters/supabase/helpers/tables/logs.ts +++ b/src/adapters/supabase/helpers/tables/logs.ts @@ -8,9 +8,9 @@ import { Database } from "../../types"; import { prettyLogs } from "../pretty-logs"; import { Super } from "./super"; import { execSync } from "child_process"; -import { Context, LogLevel } from "../../../../types"; +import { LogLevel } from "../../../../types/logs"; +import { Context } from "../../../../types/context"; import Runtime from "../../../../bindings/bot-runtime"; -import { env } from "../../../../bindings/env"; type LogFunction = (message: string, metadata?: any) => void; type LogInsert = Database["public"]["Tables"]["logs"]["Insert"]; @@ -223,12 +223,12 @@ export class Logs extends Super { }); } - constructor(supabase: SupabaseClient, context: Context) { + constructor(supabase: SupabaseClient, context: Context, environment: string, retryLimit: number, logLevel: LogLevel) { super(supabase, context); - this.environment = env.LOG_ENVIRONMENT; - this.retryLimit = env.LOG_RETRY_LIMIT; - this.maxLevel = this._getNumericLevel(env.LOG_LEVEL); + this.environment = environment; + this.retryLimit = retryLimit; + this.maxLevel = this._getNumericLevel(logLevel); } private async _sendLogsToSupabase(log: LogInsert) { diff --git a/src/bindings/env.ts b/src/bindings/env.ts index cb153d147..600cc604f 100644 --- a/src/bindings/env.ts +++ b/src/bindings/env.ts @@ -1,4 +1,4 @@ -import { EnvConfig, validateEnvConfig } from "../types"; +import { EnvConfig, validateEnvConfig } from "../types/configuration-types"; import dotenv from "dotenv"; dotenv.config(); diff --git a/src/bindings/event.ts b/src/bindings/event.ts index e6d068bcf..acf8e41a9 100644 --- a/src/bindings/event.ts +++ b/src/bindings/event.ts @@ -5,19 +5,12 @@ import { LogMessage } from "../adapters/supabase/helpers/tables/logs"; import { processors, wildcardProcessors } from "../handlers/processors"; import { validateConfigChange } from "../handlers/push"; import { addCommentToIssue, shouldSkip } from "../helpers"; -import { - GitHubEvent, - MainActionHandler, - PayloadSchema, - PostActionHandler, - PreActionHandler, - WildCardHandler, -} from "../types"; -import { Payload } from "../types/payload"; -import { ajv } from "../utils"; +import { MainActionHandler, PostActionHandler, PreActionHandler, WildCardHandler } from "../types/handlers"; +import { Payload, PayloadSchema, GitHubEvent } from "../types/payload"; +import { ajv } from "../utils/ajv"; import Runtime from "./bot-runtime"; import { loadConfiguration } from "./config"; -import { Context } from "../types"; +import { Context } from "../types/context"; const NO_VALIDATION = [GitHubEvent.INSTALLATION_ADDED_EVENT, GitHubEvent.PUSH_EVENT] as string[]; type PreHandlerWithType = { type: string; actions: PreActionHandler[] }; diff --git a/src/handlers/comment/handlers/issue/calculate-quality-score.ts b/src/handlers/comment/handlers/issue/calculate-quality-score.ts index 675518052..1fe4b6564 100644 --- a/src/handlers/comment/handlers/issue/calculate-quality-score.ts +++ b/src/handlers/comment/handlers/issue/calculate-quality-score.ts @@ -4,8 +4,6 @@ import { encodingForModel } from "js-tiktoken"; import Decimal from "decimal.js"; import Runtime from "../../../../bindings/bot-runtime"; -//const openai = new OpenAI(); // apiKey: // defaults to process.env["OPENAI_API_KEY"] - export async function calculateQualScore(issue: Issue, contributorComments: Comment[]) { const sumOfConversationTokens = countTokensOfConversation(issue, contributorComments); const estimatedOptimalModel = estimateOptimalModel(sumOfConversationTokens); @@ -56,10 +54,13 @@ export async function gptRelevance( CONVERSATION_STRINGS: string[], ARRAY_LENGTH = CONVERSATION_STRINGS.length ) { + const runtime = Runtime.getState(); + const openAi = runtime.adapters.openAi; + if (!openAi) throw new Error("OpenAI adapter is not defined"); const PROMPT = `I need to evaluate the relevance of GitHub contributors' comments to a specific issue specification. Specifically, I'm interested in how much each comment helps to further define the issue specification or contributes new information or research relevant to the issue. Please provide a float between 0 and 1 to represent the degree of relevance. A score of 1 indicates that the comment is entirely relevant and adds significant value to the issue, whereas a score of 0 indicates no relevance or added value. Each contributor's comment is on a new line.\n\nIssue Specification:\n\`\`\`\n${ISSUE_SPECIFICATION_BODY}\n\`\`\`\n\nConversation:\n\`\`\`\n${CONVERSATION_STRINGS.join( "\n" )}\n\`\`\`\n\n\nTo what degree are each of the comments in the conversation relevant and valuable to further defining the issue specification? Please reply with an array of float numbers between 0 and 1, corresponding to each comment in the order they appear. Each float should represent the degree of relevance and added value of the comment to the issue. The total length of the array in your response should equal exactly ${ARRAY_LENGTH} elements.`; - const response: OpenAI.Chat.ChatCompletion = await openai.chat.completions.create({ + const response: OpenAI.Chat.ChatCompletion = await openAi.chat.completions.create({ model: model, messages: [ { diff --git a/src/types/configuration-types.ts b/src/types/configuration-types.ts index 4ae95900c..b62bea022 100644 --- a/src/types/configuration-types.ts +++ b/src/types/configuration-types.ts @@ -2,7 +2,7 @@ import { Type as T, Static, TProperties, TObject, ObjectOptions, StringOptions, import { LogLevel } from "../types"; import { validHTMLElements } from "../handlers/comment/handlers/issue/valid-html-elements"; import { userCommands } from "../handlers"; -import { ajv } from "../utils"; +import { ajv } from "../utils/ajv"; import ms from "ms"; const promotionComment = @@ -35,106 +35,6 @@ const defaultPriorityLabels = [ { name: "Priority: 5 (Emergency)" }, ]; -/* -export const EnvConfigSchema = z.object({ - WEBHOOK_PROXY_URL: z.string().url(), - LOG_ENVIRONMENT: z.string().default("development"), - LOG_LEVEL: z.nativeEnum(LogLevel).default(LogLevel.SILLY), - LOG_RETRY_LIMIT: z.number().default(8), - SUPABASE_URL: z.string().url(), - SUPABASE_KEY: z.string(), - X25519_PRIVATE_KEY: z.string(), - PRIVATE_KEY: z.string(), - APP_ID: z.number(), -}); - -export type EnvConfig = z.infer; - -export const BotConfigSchema = z.strictObject({ - keys: z.strictObject({ - evmPrivateEncrypted: z.string().optional(), - openAi: z.string().optional(), - }), - features: z.strictObject({ - assistivePricing: z.boolean().default(false), - defaultLabels: z.string().array().default([]), - newContributorGreeting: z - .strictObject({ - header: z.string().default( - "Thank you for contributing! \ - Please be sure to set your wallet address \ - before completing your first task so that you can \ - collect your reward." - ), - displayHelpMenu: z.boolean().default(true), - footer: z.string().default(promotionComment), - }) - .default({}), - publicAccessControl: z - .strictObject({ - setLabel: z.boolean().default(true), - fundExternalClosedIssue: z.boolean().default(true), - }) - .default({}), - }), - timers: z - .strictObject({ - reviewDelayTolerance: z.string().default("1 day"), - taskStaleTimeoutDuration: z.string().default("1 month"), - taskFollowUpDuration: z.string().default("0.5 weeks"), - taskDisqualifyDuration: z.string().default("1 week"), - }) - .default({}), - payments: z - .strictObject({ - maxPermitPrice: z.number().default(Number.MAX_SAFE_INTEGER), - evmNetworkId: z.number().default(1), - basePriceMultiplier: z.number().default(1), - issueCreatorMultiplier: z.number().default(1), - }) - .default({}), - commands: z.array( - z.strictObject({ - name: z.string(), - enabled: z.boolean(), - }) - ), - incentives: z - .strictObject({ - comment: z - .strictObject({ - elements: z.record(z.union(HtmlEntities), z.number()).default(allHtmlElementsSetToZero), - totals: z - .strictObject({ - character: z.number().default(0), - word: z.number().default(0), - sentence: z.number().default(0), - paragraph: z.number().default(0), - comment: z.number().default(0), - }) - .default({}), - }) - .default({}), - }) - .default({}), - labels: z - .strictObject({ - time: z.array(z.strictObject({ name: z.string() })).default(defaultTimeLabels), - priority: z.array(z.strictObject({ name: z.string() })).default(defaultPriorityLabels), - }) - .default({}), - miscellaneous: z - .strictObject({ - maxConcurrentTasks: z.number().default(Number.MAX_SAFE_INTEGER), - promotionComment: z.string().default(promotionComment), - registerWalletWithVerification: z.boolean().default(false), - }) - .default({}), -}); - -export type BotConfig = z.infer; -*/ - function StrictObject(obj: T, options?: ObjectOptions): TObject { return T.Object(obj, { additionalProperties: false, default: {}, ...options }); } @@ -164,69 +64,72 @@ export const EnvConfigSchema = T.Object({ export const validateEnvConfig = ajv.compile(EnvConfigSchema); export type EnvConfig = Static; -export const BotConfigSchema = StrictObject({ - keys: StrictObject({ - evmPrivateEncrypted: T.String(), - openAi: T.Optional(T.String()), - }), - features: StrictObject({ - assistivePricing: T.Boolean({ default: false }), - defaultLabels: T.Array(T.String(), { default: [] }), - newContributorGreeting: StrictObject({ - enabled: T.Boolean({ default: false }), - header: T.String({ default: defaultGreetingHeader }), - displayHelpMenu: T.Boolean({ default: true }), - footer: T.String({ default: promotionComment }), +export const BotConfigSchema = StrictObject( + { + keys: StrictObject({ + evmPrivateEncrypted: T.String(), + openAi: T.Optional(T.String()), + }), + features: StrictObject({ + assistivePricing: T.Boolean({ default: false }), + defaultLabels: T.Array(T.String(), { default: [] }), + newContributorGreeting: StrictObject({ + enabled: T.Boolean({ default: false }), + header: T.String({ default: defaultGreetingHeader }), + displayHelpMenu: T.Boolean({ default: true }), + footer: T.String({ default: promotionComment }), + }), + publicAccessControl: StrictObject({ + setLabel: T.Boolean({ default: true }), + fundExternalClosedIssue: T.Boolean({ default: true }), + }), }), - publicAccessControl: StrictObject({ - setLabel: T.Boolean({ default: true }), - fundExternalClosedIssue: T.Boolean({ default: true }), + openai: StrictObject({ + tokenLimit: T.Number({ default: 100000 }), }), - }), - openai: StrictObject({ - tokenLimit: T.Number({ default: 100000 }), - }), - timers: StrictObject({ - reviewDelayTolerance: stringDuration({ default: "1 day" }), - taskStaleTimeoutDuration: stringDuration({ default: "1 month" }), - taskFollowUpDuration: stringDuration({ default: "0.5 weeks" }), - taskDisqualifyDuration: stringDuration({ default: "1 week" }), - }), - payments: StrictObject({ - maxPermitPrice: T.Number({ default: Number.MAX_SAFE_INTEGER }), - evmNetworkId: T.Number({ default: 1 }), - basePriceMultiplier: T.Number({ default: 1 }), - issueCreatorMultiplier: T.Number({ default: 1 }), - }), - commands: T.Array( - StrictObject({ - name: T.String(), - enabled: T.Boolean(), + timers: StrictObject({ + reviewDelayTolerance: stringDuration({ default: "1 day" }), + taskStaleTimeoutDuration: stringDuration({ default: "1 month" }), + taskFollowUpDuration: stringDuration({ default: "0.5 weeks" }), + taskDisqualifyDuration: stringDuration({ default: "1 week" }), }), - { default: allCommands } - ), - incentives: StrictObject({ - comment: StrictObject({ - elements: T.Record(T.Union(HtmlEntities), T.Number(), { default: allHtmlElementsSetToZero }), - totals: StrictObject({ - character: T.Number({ default: 0, minimum: 0 }), - word: T.Number({ default: 0, minimum: 0 }), - sentence: T.Number({ default: 0, minimum: 0 }), - paragraph: T.Number({ default: 0, minimum: 0 }), - comment: T.Number({ default: 0, minimum: 0 }), + payments: StrictObject({ + maxPermitPrice: T.Number({ default: Number.MAX_SAFE_INTEGER }), + evmNetworkId: T.Number({ default: 1 }), + basePriceMultiplier: T.Number({ default: 1 }), + issueCreatorMultiplier: T.Number({ default: 1 }), + }), + commands: T.Array( + StrictObject({ + name: T.String(), + enabled: T.Boolean(), + }), + { default: allCommands } + ), + incentives: StrictObject({ + comment: StrictObject({ + elements: T.Record(T.Union(HtmlEntities), T.Number(), { default: allHtmlElementsSetToZero }), + totals: StrictObject({ + character: T.Number({ default: 0, minimum: 0 }), + word: T.Number({ default: 0, minimum: 0 }), + sentence: T.Number({ default: 0, minimum: 0 }), + paragraph: T.Number({ default: 0, minimum: 0 }), + comment: T.Number({ default: 0, minimum: 0 }), + }), }), }), - }), - labels: StrictObject({ - time: T.Array(StrictObject({ name: T.String() }), { default: defaultTimeLabels }), - priority: T.Array(StrictObject({ name: T.String() }), { default: defaultPriorityLabels }), - }), - miscellaneous: StrictObject({ - maxConcurrentTasks: T.Number({ default: Number.MAX_SAFE_INTEGER }), - promotionComment: T.String({ default: promotionComment }), - registerWalletWithVerification: T.Boolean({ default: false }), - }), -}); + labels: StrictObject({ + time: T.Array(StrictObject({ name: T.String() }), { default: defaultTimeLabels }), + priority: T.Array(StrictObject({ name: T.String() }), { default: defaultPriorityLabels }), + }), + miscellaneous: StrictObject({ + maxConcurrentTasks: T.Number({ default: Number.MAX_SAFE_INTEGER }), + promotionComment: T.String({ default: promotionComment }), + registerWalletWithVerification: T.Boolean({ default: false }), + }), + }, + { default: undefined } +); export const validateBotConfig = ajv.compile(BotConfigSchema); export type BotConfig = StaticDecode; diff --git a/src/utils/ajv.ts b/src/utils/ajv.ts index 0ea84cc3f..87c71bca3 100644 --- a/src/utils/ajv.ts +++ b/src/utils/ajv.ts @@ -7,6 +7,7 @@ export const ajv = addFormats( removeAdditional: true, useDefaults: true, allErrors: true, + coerceTypes: true, }), { formats: [