diff --git a/worker/src/task/1-task.ts b/worker/src/task/1-task.ts index 742664d..1fc6a77 100644 --- a/worker/src/task/1-task.ts +++ b/worker/src/task/1-task.ts @@ -1,4 +1,4 @@ -import { getOrcaClient } from "@_koii/task-manager/extensions"; + import { namespaceWrapper, TASK_ID } from "@_koii/namespace-wrapper"; import "dotenv/config"; import { status, middleServerUrl } from "../utils/constant"; @@ -9,6 +9,8 @@ import { LogLevel } from "@_koii/namespace-wrapper/dist/types"; import { actionMessage } from "../utils/constant"; import { errorMessage } from "../utils/constant"; import { v4 as uuidv4 } from "uuid"; +import { handleOrcaClientCreation, handleRequest } from "../utils/orcaHandler/orcaHandler"; + dotenv.config(); export async function task(roundNumber: number): Promise { @@ -22,6 +24,7 @@ export async function task(roundNumber: number): Promise { // Changed from 3 to 4 to have more time if (roundNumber >= 4) { const triggerFetchAuditResult = await fetch(`${middleServerUrl}/summarizer/worker/update-audit-result`, { + const triggerFetchAuditResult = await fetch(`${middleServerUrl}/api/summarizer/trigger-fetch-audit-result`, { method: "POST", headers: { "Content-Type": "application/json", @@ -34,7 +37,14 @@ export async function task(roundNumber: number): Promise { } console.log(`[TASK] EXECUTE TASK FOR ROUND ${roundNumber}`); try { - const orcaClient = await getOrcaClient(); + let orcaClient; + try { + orcaClient = await handleOrcaClientCreation(); + }catch{ + await namespaceWrapper.logMessage(LogLevel.Error, errorMessage.NO_ORCA_CLIENT, actionMessage.NO_ORCA_CLIENT); + await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NO_ORCA_CLIENT); + return; + } // check if the env variable is valid if (!process.env.ANTHROPIC_API_KEY) { await namespaceWrapper.logMessage( @@ -83,11 +93,7 @@ export async function task(roundNumber: number): Promise { await namespaceWrapper.storeSet(`result-${roundNumber}`, status.GITHUB_CHECK_FAILED); return; } - if (!orcaClient) { - await namespaceWrapper.logMessage(LogLevel.Error, errorMessage.NO_ORCA_CLIENT, actionMessage.NO_ORCA_CLIENT); - await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NO_ORCA_CLIENT); - return; - } + const stakingKeypair = await namespaceWrapper.getSubmitterAccount(); if (!stakingKeypair) { @@ -155,12 +161,45 @@ export async function task(roundNumber: number): Promise { }, body: JSON.stringify(jsonBody), }); + const repoSummaryResponse = await handleRequest({orcaClient, route: `repo_summary/${roundNumber}`, bodyJSON: jsonBody}); console.log("[TASK] repoSummaryResponse: ", repoSummaryResponse); if (repoSummaryResponse.status !== 200) { await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED); + console.log("[TASK] repoSummaryResponse.data.result.data ", repoSummaryResponse.data.result.data); + const payload = { + taskId: TASK_ID, + action: "add", + roundNumber: roundNumber, + prUrl: repoSummaryResponse.data.result.data.pr_url, + stakingKey: stakingKey + } + console.log("[TASK] Signing payload: ", payload); + if (repoSummaryResponse.status === 200) { + try{ + const signature = await namespaceWrapper.payloadSigning( + payload, + stakingKeypair.secretKey, + ); + console.log("[TASK] signature: ", signature); + const addPrToSummarizerTodoResponse = await fetch(`${middleServerUrl}/api/summarizer/add-pr-to-summarizer-todo`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ signature: signature, stakingKey: stakingKey }), + }); + console.log("[TASK] addPrToSummarizerTodoResponse: ", addPrToSummarizerTodoResponse); + }catch(error){ + await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_FAILED_TO_ADD_PR_TO_SUMMARIZER_TODO); + console.error("[TASK] Error adding PR to summarizer todo:", error); + } + await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUCCESSFULLY_SUMMARIZED); + } else { + await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_FAILED_TO_BE_SUMMARIZED); } } catch (error) { await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED); + await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_FAILED_TO_BE_SUMMARIZED); console.error("[TASK] EXECUTE TASK ERROR:", error); } } catch (error) { diff --git a/worker/src/task/2-submission.ts b/worker/src/task/2-submission.ts index e7686d3..6869004 100644 --- a/worker/src/task/2-submission.ts +++ b/worker/src/task/2-submission.ts @@ -1,5 +1,5 @@ import { storeFile } from "../utils/ipfs"; -import { getOrcaClient } from "@_koii/task-manager/extensions"; +import { handleOrcaClientCreation, handleRequest } from "../utils/orcaHandler/orcaHandler"; import { namespaceWrapper, TASK_ID } from "@_koii/namespace-wrapper"; import { status } from "../utils/constant"; export async function submission(roundNumber: number) : Promise { @@ -13,11 +13,14 @@ export async function submission(roundNumber: number) : Promise { try { console.log("[SUBMISSION] Initializing Orca client..."); - const orcaClient = await getOrcaClient(); - if (!orcaClient) { + let orcaClient; + try { + orcaClient = await handleOrcaClientCreation(); + }catch{ console.error("[SUBMISSION] Failed to initialize Orca client"); return; } + console.log("[SUBMISSION] Orca client initialized successfully"); console.log(`[SUBMISSION] Fetching task result for round ${roundNumber}...`); @@ -34,7 +37,7 @@ export async function submission(roundNumber: number) : Promise { } console.log(`[SUBMISSION] Fetching submission data for round ${roundNumber}...`); - const result = await orcaClient.podCall(`submission/${roundNumber}`); + const result = await handleRequest({orcaClient, route: `submission/${roundNumber}`, bodyJSON: { taskId: TASK_ID, roundNumber }}); let submission; console.log("[SUBMISSION] Submission result:", result.data); diff --git a/worker/src/task/3-audit.ts b/worker/src/task/3-audit.ts index fb92783..280d6b1 100644 --- a/worker/src/task/3-audit.ts +++ b/worker/src/task/3-audit.ts @@ -1,6 +1,6 @@ -import { getOrcaClient } from "@_koii/task-manager/extensions"; import { middleServerUrl, status } from "../utils/constant"; import { submissionJSONSignatureDecode } from "../utils/submissionJSONSignatureDecode"; +import { handleOrcaClientCreation, handleRequest } from "../utils/orcaHandler/orcaHandler"; // import { status } from '../utils/constant' export async function audit(cid: string, roundNumber: number, submitterKey: string): Promise { /** @@ -11,11 +11,13 @@ export async function audit(cid: string, roundNumber: number, submitterKey: stri */ try { - const orcaClient = await getOrcaClient(); - if (!orcaClient) { - // await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NO_ORCA_CLIENT); + let orcaClient; + try { + orcaClient = await handleOrcaClientCreation(); + }catch{ return; } + // Check if the cid is one of the status if (Object.values(status).includes(cid)) { // This returns a dummy true diff --git a/worker/src/utils/constant.ts b/worker/src/utils/constant.ts index 7698a76..fca6985 100644 --- a/worker/src/utils/constant.ts +++ b/worker/src/utils/constant.ts @@ -58,3 +58,5 @@ export const defaultBountyMarkdownFile = export const customReward = 400 * 10 ** 9; // This should be in ROE! export const middleServerUrl = "https://ik8kcow8ksw8gwgoo0ggosko.dev.koii.network"; + +export const middleServerUrl = "https://builder247-prod.dev.koii.network" \ No newline at end of file diff --git a/worker/src/utils/orcaHandler/orcaHandler.ts b/worker/src/utils/orcaHandler/orcaHandler.ts new file mode 100644 index 0000000..b5afe57 --- /dev/null +++ b/worker/src/utils/orcaHandler/orcaHandler.ts @@ -0,0 +1,46 @@ + +import dotenv from "dotenv"; +dotenv.config(); + + +import { getOrcaClient } from "@_koii/task-manager/extensions"; +export async function handleOrcaClientCreation(){ + try { + // if (process.env.NODE_ENV !== "development") { + // const { getOrcaClient } = await import("@_koii/task-manager/extensions"); + const orcaClient = await getOrcaClient(); + if (!orcaClient) { + throw new Error("Orca client not found"); + } + return orcaClient; + // }else{ + // return null; + // } + }catch{ + throw new Error("Orca client not found"); + } +} +export async function handleRequest({orcaClient, route, bodyJSON}:{orcaClient:any, route:string, bodyJSON:any}){ + // if (process.env.NODE_ENV === "development") { + // const response = await fetch(`${process.env.LOCAL_CONTAINER_TEST_URL}/${route}`, { + // method: "POST", + // headers: { + // "Content-Type": "application/json", + // }, + // body: JSON.stringify(bodyJSON), + // }); + // return response; + // }else{ + if (!orcaClient) { + throw new Error("Orca client not found"); + } + const response = await orcaClient.podCall(`${route}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(bodyJSON), + }); + return response; + // } +} diff --git a/worker/tests/stages/audit_summary.py b/worker/tests/stages/audit_summary.py new file mode 100644 index 0000000..1317879 --- /dev/null +++ b/worker/tests/stages/audit_summary.py @@ -0,0 +1,51 @@ +"""Test stage for auditing summary.""" + +import requests +from prometheus_test import Context + + +async def prepare(context: Context, target_name: str): + """Prepare for auditing summary.""" + staking_key = context.env.get("WORKER_ID") + target_submission = await context.storeGet(f"submission-{target_name}") + + return { + "staking_key": staking_key, + "round_number": context.round_number, + "target_submission": target_submission, + "target_name": target_name, + } + + +async def execute(context: Context, prepare_data: dict): + """Execute summary audit test.""" + staking_key = prepare_data["staking_key"] + round_number = prepare_data["round_number"] + target_submission = prepare_data["target_submission"] + target_name = prepare_data["target_name"] + + # Mock response for audit + response = requests.post( + "http://localhost:5000/api/summarizer/audit", + json={ + "taskId": context.config.task_id, + "roundNumber": round_number, + "stakingKey": staking_key, + "submitterKey": target_name, + "cid": target_submission.get("cid"), + "prUrl": target_submission.get("pr_url"), + "githubUsername": target_submission.get("github_username"), + }, + ) + + if response.status_code != 200: + raise Exception(f"Failed to audit summary: {response.text}") + + result = response.json() + if not result.get("success"): + raise Exception("Failed to audit summary") + + # Store audit result + await context.storeSet(f"audit-{staking_key}-{target_name}", result.get("data")) + + return True diff --git a/worker/tests/stages/fetch_summarizer_todo.py b/worker/tests/stages/fetch_summarizer_todo.py new file mode 100644 index 0000000..582d03a --- /dev/null +++ b/worker/tests/stages/fetch_summarizer_todo.py @@ -0,0 +1,39 @@ +"""Test stage for fetching summarizer todo.""" + +import requests +from prometheus_test import Context + + +async def prepare(context: Context): + """Prepare for fetching summarizer todo.""" + return { + "staking_key": context.env.get("WORKER_ID"), + "round_number": context.round_number, + } + + +async def execute(context: Context, prepare_data: dict): + """Execute fetch summarizer todo test.""" + staking_key = prepare_data["staking_key"] + round_number = prepare_data["round_number"] + + # Mock response for fetching todo + response = requests.post( + "http://localhost:5000/api/summarizer/fetch-summarizer-todo", + json={ + "stakingKey": staking_key, + "roundNumber": round_number, + }, + ) + + if response.status_code != 200: + raise Exception(f"Failed to fetch summarizer todo: {response.text}") + + result = response.json() + if not result.get("success"): + raise Exception("Failed to fetch summarizer todo") + + # Store todo data for next steps + await context.storeSet(f"todo-{staking_key}", result.get("data")) + + return True diff --git a/worker/tests/stages/generate_summary.py b/worker/tests/stages/generate_summary.py new file mode 100644 index 0000000..ee0ae24 --- /dev/null +++ b/worker/tests/stages/generate_summary.py @@ -0,0 +1,47 @@ +"""Test stage for generating repository summary.""" + +import requests +from prometheus_test import Context + + +async def prepare(context: Context): + """Prepare for generating summary.""" + staking_key = context.env.get("WORKER_ID") + todo = await context.storeGet(f"todo-{staking_key}") + + return { + "staking_key": staking_key, + "round_number": context.round_number, + "repo_owner": todo.get("repo_owner"), + "repo_name": todo.get("repo_name"), + } + + +async def execute(context: Context, prepare_data: dict): + """Execute summary generation test.""" + staking_key = prepare_data["staking_key"] + round_number = prepare_data["round_number"] + repo_owner = prepare_data["repo_owner"] + repo_name = prepare_data["repo_name"] + + # Mock response for repo summary generation + response = requests.post( + "http://localhost:5000/api/summarizer/generate-summary", + json={ + "taskId": context.config.task_id, + "round_number": str(round_number), + "repo_url": f"https://github.com/{repo_owner}/{repo_name}", + }, + ) + + if response.status_code != 200: + raise Exception(f"Failed to generate summary: {response.text}") + + result = response.json() + if not result.get("success"): + raise Exception("Failed to generate summary") + + # Store PR URL for next steps + await context.storeSet(f"pr-{staking_key}", result.get("data", {}).get("pr_url")) + + return True diff --git a/worker/tests/stages/submit_summary.py b/worker/tests/stages/submit_summary.py new file mode 100644 index 0000000..5cd4739 --- /dev/null +++ b/worker/tests/stages/submit_summary.py @@ -0,0 +1,56 @@ +"""Test stage for submitting summary.""" + +import requests +from prometheus_test import Context + + +async def prepare(context: Context): + """Prepare for submitting summary.""" + staking_key = context.env.get("WORKER_ID") + pr_url = await context.storeGet(f"pr-{staking_key}") + + return { + "staking_key": staking_key, + "round_number": context.round_number, + "pr_url": pr_url, + "github_username": context.env.get("GITHUB_USERNAME"), + } + + +async def execute(context: Context, prepare_data: dict): + """Execute summary submission test.""" + staking_key = prepare_data["staking_key"] + round_number = prepare_data["round_number"] + pr_url = prepare_data["pr_url"] + github_username = prepare_data["github_username"] + + # Mock response for submission + response = requests.post( + "http://localhost:5000/api/summarizer/submit", + json={ + "taskId": context.config.task_id, + "roundNumber": round_number, + "prUrl": pr_url, + "stakingKey": staking_key, + "githubUsername": github_username, + }, + ) + + if response.status_code != 200: + raise Exception(f"Failed to submit summary: {response.text}") + + result = response.json() + if not result.get("success"): + raise Exception("Failed to submit summary") + + # Store submission data for audit + await context.storeSet( + f"submission-{staking_key}", + { + "cid": result.get("data", {}).get("cid"), + "pr_url": pr_url, + "github_username": github_username, + }, + ) + + return True diff --git a/worker/tests/stages/validate_api_keys.py b/worker/tests/stages/validate_api_keys.py new file mode 100644 index 0000000..5c3ef27 --- /dev/null +++ b/worker/tests/stages/validate_api_keys.py @@ -0,0 +1,31 @@ +"""Test stage for validating API keys.""" + +import requests +from prometheus_test import Context + + +async def prepare(context: Context): + """Prepare for API key validation test.""" + return { + "api_key": context.env.get("ANTHROPIC_API_KEY"), + } + + +async def execute(context: Context, prepare_data: dict): + """Execute API key validation test.""" + api_key = prepare_data["api_key"] + + # Mock response for Anthropic API validation + response = requests.post( + "http://localhost:5000/api/summarizer/validate-api-key", + json={"api_key": api_key}, + ) + + if response.status_code != 200: + raise Exception(f"API key validation failed: {response.text}") + + result = response.json() + if not result.get("valid"): + raise Exception("API key is not valid") + + return True