update submission logic and cron job version of task
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
|
import { task } from "../utils/task/task";
|
||||||
export async function setup(): Promise<void> {
|
export async function setup(): Promise<void> {
|
||||||
// define any steps that must be executed before the task starts
|
// Setup a cron job to run every 1 minutes
|
||||||
console.log("CUSTOM SETUP");
|
task();
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,13 @@ import { namespaceWrapper, TASK_ID } from "@_koii/namespace-wrapper";
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import { status, middleServerUrl } from "../utils/constant";
|
import { status, middleServerUrl } from "../utils/constant";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { checkAnthropicAPIKey, isValidAnthropicApiKey } from "../utils/anthropicCheck";
|
// import { checkAnthropicAPIKey, isValidAnthropicApiKey } from "../utils/check/anthropicCheck";
|
||||||
import { checkGitHub } from "../utils/githubCheck";
|
// import { checkGitHub } from "../utils/check/githubCheck";
|
||||||
import { LogLevel } from "@_koii/namespace-wrapper/dist/types";
|
import { LogLevel } from "@_koii/namespace-wrapper/dist/types";
|
||||||
import { actionMessage } from "../utils/constant";
|
import { actionMessage } from "../utils/constant";
|
||||||
import { errorMessage } from "../utils/constant";
|
import { errorMessage } from "../utils/constant";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import { preRunCheck } from "../utils/check/checks";
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
export async function task(roundNumber: number): Promise<void> {
|
export async function task(roundNumber: number): Promise<void> {
|
||||||
@ -20,176 +21,15 @@ export async function task(roundNumber: number): Promise<void> {
|
|||||||
// FORCE TO PAUSE 30 SECONDS
|
// FORCE TO PAUSE 30 SECONDS
|
||||||
// No submission on Round 0 so no need to trigger fetch audit result before round 3
|
// No submission on Round 0 so no need to trigger fetch audit result before round 3
|
||||||
// Changed from 3 to 4 to have more time
|
// Changed from 3 to 4 to have more time
|
||||||
if (roundNumber >= 4) {
|
|
||||||
const triggerFetchAuditResult = await fetch(`${middleServerUrl}/summarizer/worker/update-audit-result`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ taskId: TASK_ID, round: roundNumber - 4 }),
|
|
||||||
});
|
|
||||||
console.log(
|
|
||||||
`[TASK] Trigger fetch audit result for round ${roundNumber - 3}. Result is ${triggerFetchAuditResult.status}.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
console.log(`[TASK] EXECUTE TASK FOR ROUND ${roundNumber}`);
|
|
||||||
try {
|
|
||||||
const orcaClient = await getOrcaClient();
|
|
||||||
// check if the env variable is valid
|
|
||||||
if (!process.env.ANTHROPIC_API_KEY) {
|
|
||||||
await namespaceWrapper.logMessage(
|
|
||||||
LogLevel.Error,
|
|
||||||
errorMessage.ANTHROPIC_API_KEY_INVALID,
|
|
||||||
actionMessage.ANTHROPIC_API_KEY_INVALID,
|
|
||||||
);
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ANTHROPIC_API_KEY_INVALID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isValidAnthropicApiKey(process.env.ANTHROPIC_API_KEY!)) {
|
|
||||||
await namespaceWrapper.logMessage(
|
|
||||||
LogLevel.Error,
|
|
||||||
errorMessage.ANTHROPIC_API_KEY_INVALID,
|
|
||||||
actionMessage.ANTHROPIC_API_KEY_INVALID,
|
|
||||||
);
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ANTHROPIC_API_KEY_INVALID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const isAnthropicAPIKeyValid = await checkAnthropicAPIKey(process.env.ANTHROPIC_API_KEY!);
|
|
||||||
if (!isAnthropicAPIKeyValid) {
|
|
||||||
await namespaceWrapper.logMessage(
|
|
||||||
LogLevel.Error,
|
|
||||||
errorMessage.ANTHROPIC_API_KEY_NO_CREDIT,
|
|
||||||
actionMessage.ANTHROPIC_API_KEY_NO_CREDIT,
|
|
||||||
);
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ANTHROPIC_API_KEY_NO_CREDIT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!process.env.GITHUB_USERNAME || !process.env.GITHUB_TOKEN) {
|
|
||||||
await namespaceWrapper.logMessage(
|
|
||||||
LogLevel.Error,
|
|
||||||
errorMessage.GITHUB_CHECK_FAILED,
|
|
||||||
actionMessage.GITHUB_CHECK_FAILED,
|
|
||||||
);
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.GITHUB_CHECK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const isGitHubValid = await checkGitHub(process.env.GITHUB_USERNAME!, process.env.GITHUB_TOKEN!);
|
|
||||||
if (!isGitHubValid) {
|
|
||||||
await namespaceWrapper.logMessage(
|
|
||||||
LogLevel.Error,
|
|
||||||
errorMessage.GITHUB_CHECK_FAILED,
|
|
||||||
actionMessage.GITHUB_CHECK_FAILED,
|
|
||||||
);
|
|
||||||
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 (roundNumber >= 4) {
|
||||||
if (!stakingKeypair) {
|
// const auditRound = roundNumber - 4;
|
||||||
throw new Error("No staking keypair found");
|
// const response = await fetch(`${middleServerUrl}/summarizer/worker/update-audit-result`, {
|
||||||
}
|
// method: "POST",
|
||||||
const stakingKey = stakingKeypair.publicKey.toBase58();
|
// headers: { "Content-Type": "application/json" },
|
||||||
const pubKey = await namespaceWrapper.getMainAccountPubkey();
|
// body: JSON.stringify({ taskId: TASK_ID, round: auditRound }),
|
||||||
if (!pubKey) {
|
// });
|
||||||
throw new Error("No public key found");
|
// console.log(`[TASK] Fetched audit result for round ${auditRound}. Status: ${response.status}`);
|
||||||
}
|
// }
|
||||||
|
// console.log(`[TASK] EXECUTE TASK FOR ROUND ${roundNumber}`);
|
||||||
/****************** All these issues need to be generate a markdown file ******************/
|
|
||||||
|
|
||||||
const signature = await namespaceWrapper.payloadSigning(
|
|
||||||
{
|
|
||||||
taskId: TASK_ID,
|
|
||||||
roundNumber: roundNumber,
|
|
||||||
action: "fetch-todo",
|
|
||||||
githubUsername: stakingKey,
|
|
||||||
stakingKey: stakingKey,
|
|
||||||
},
|
|
||||||
stakingKeypair.secretKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
// const initializedDocumentSummarizeIssues = await getInitializedDocumentSummarizeIssues(existingIssues);
|
|
||||||
|
|
||||||
console.log(`[TASK] Making Request to Middle Server with taskId: ${TASK_ID} and round: ${roundNumber}`);
|
|
||||||
|
|
||||||
let requiredWorkResponse: Response = new Response();
|
|
||||||
let retryCount = 0;
|
|
||||||
const maxRetries = 36; // 6 minutes with 10 second intervals
|
|
||||||
const retryDelay = 10000; // 10 seconds in milliseconds
|
|
||||||
|
|
||||||
while (retryCount < maxRetries) {
|
|
||||||
requiredWorkResponse = await fetch(`${middleServerUrl}/summarizer/worker/fetch-todo`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ signature: signature, stakingKey: stakingKey }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (requiredWorkResponse.status === 200) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[TASK] Server returned status ${requiredWorkResponse.status}, retrying in ${retryDelay/1000} seconds... (Attempt ${retryCount + 1}/${maxRetries})`);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
|
||||||
retryCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the response is 200 after all retries
|
|
||||||
if (requiredWorkResponse.status !== 200) {
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NO_ISSUES_PENDING_TO_BE_SUMMARIZED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const requiredWorkResponseData = await requiredWorkResponse.json();
|
|
||||||
console.log("[TASK] requiredWorkResponseData: ", requiredWorkResponseData);
|
|
||||||
const uuid = uuidv4();
|
|
||||||
const alreadyAssigned = await namespaceWrapper.storeGet(JSON.stringify(requiredWorkResponseData.data.id));
|
|
||||||
if (alreadyAssigned) {
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NOT_FINISHED_TASK);
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
await namespaceWrapper.storeSet(JSON.stringify(requiredWorkResponseData.data.id), "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
await namespaceWrapper.storeSet(`uuid-${roundNumber}`, uuid);
|
|
||||||
|
|
||||||
const podcallPayload = {
|
|
||||||
taskId: TASK_ID,
|
|
||||||
roundNumber,
|
|
||||||
uuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
const podCallSignature = await namespaceWrapper.payloadSigning(podcallPayload, stakingKeypair.secretKey);
|
|
||||||
|
|
||||||
const jsonBody = {
|
|
||||||
task_id: TASK_ID,
|
|
||||||
round_number: roundNumber,
|
|
||||||
repo_url: `https://github.com/${requiredWorkResponseData.data.repo_owner}/${requiredWorkResponseData.data.repo_name}`,
|
|
||||||
podcall_signature: podCallSignature,
|
|
||||||
};
|
|
||||||
console.log("[TASK] jsonBody: ", jsonBody);
|
|
||||||
try {
|
|
||||||
const repoSummaryResponse = await orcaClient.podCall(`worker-task/${roundNumber}`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(jsonBody),
|
|
||||||
});
|
|
||||||
console.log("[TASK] repoSummaryResponse: ", repoSummaryResponse);
|
|
||||||
if (repoSummaryResponse.status !== 200) {
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED);
|
|
||||||
console.error("[TASK] EXECUTE TASK ERROR:", error);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
await namespaceWrapper.storeSet(`result-${roundNumber}`, status.UNKNOWN_ERROR);
|
|
||||||
console.error("[TASK] EXECUTE TASK ERROR:", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -3,7 +3,21 @@ import { getOrcaClient } from "@_koii/task-manager/extensions";
|
|||||||
import { namespaceWrapper, TASK_ID } from "@_koii/namespace-wrapper";
|
import { namespaceWrapper, TASK_ID } from "@_koii/namespace-wrapper";
|
||||||
import { middleServerUrl, status } from "../utils/constant";
|
import { middleServerUrl, status } from "../utils/constant";
|
||||||
import { preRunCheck } from "../utils/check/checks";
|
import { preRunCheck } from "../utils/check/checks";
|
||||||
export async function submission(roundNumber: number) : Promise<string | void> {
|
|
||||||
|
interface SubmissionData {
|
||||||
|
prUrl: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SubmissionParams {
|
||||||
|
orcaClient: any;
|
||||||
|
roundNumber: number;
|
||||||
|
stakingKey: string;
|
||||||
|
publicKey: string;
|
||||||
|
secretKey: Uint8Array<ArrayBufferLike>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function submission(roundNumber: number): Promise<string | void> {
|
||||||
/**
|
/**
|
||||||
* Retrieve the task proofs from your container and submit for auditing
|
* Retrieve the task proofs from your container and submit for auditing
|
||||||
* Must return a string of max 512 bytes to be submitted on chain
|
* Must return a string of max 512 bytes to be submitted on chain
|
||||||
@ -25,20 +39,21 @@ export async function submission(roundNumber: number) : Promise<string | void> {
|
|||||||
console.log(`[SUBMISSION] Starting submission process for round ${roundNumber}`);
|
console.log(`[SUBMISSION] Starting submission process for round ${roundNumber}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("[SUBMISSION] Initializing Orca client...");
|
const orcaClient = await initializeOrcaClient();
|
||||||
const orcaClient = await getOrcaClient();
|
|
||||||
if (!orcaClient) {
|
|
||||||
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}...`);
|
|
||||||
const shouldMakeSubmission = await namespaceWrapper.storeGet(`shouldMakeSubmission`);
|
const shouldMakeSubmission = await namespaceWrapper.storeGet(`shouldMakeSubmission`);
|
||||||
|
|
||||||
if (!shouldMakeSubmission || shouldMakeSubmission !== "true") {
|
if (!shouldMakeSubmission || shouldMakeSubmission !== "true") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cid = await makeSubmission({orcaClient, roundNumber, stakingKey, publicKey: pubKey, secretKey});
|
const cid = await makeSubmission({
|
||||||
|
orcaClient,
|
||||||
|
roundNumber,
|
||||||
|
stakingKey,
|
||||||
|
publicKey: pubKey,
|
||||||
|
secretKey
|
||||||
|
});
|
||||||
|
|
||||||
return cid || void 0;
|
return cid || void 0;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[SUBMISSION] Error during submission process:", error);
|
console.error("[SUBMISSION] Error during submission process:", error);
|
||||||
@ -46,77 +61,127 @@ export async function submission(roundNumber: number) : Promise<string | void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function makeSubmission({orcaClient, roundNumber, stakingKey, publicKey, secretKey}: {orcaClient: any, roundNumber: number, stakingKey: string, publicKey: string, secretKey: Uint8Array<ArrayBufferLike>}) {
|
async function initializeOrcaClient() {
|
||||||
|
console.log("[SUBMISSION] Initializing Orca client...");
|
||||||
|
const orcaClient = await getOrcaClient();
|
||||||
|
|
||||||
|
if (!orcaClient) {
|
||||||
|
console.error("[SUBMISSION] Failed to initialize Orca client");
|
||||||
|
throw new Error("Failed to initialize Orca client");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[SUBMISSION] Orca client initialized successfully");
|
||||||
|
return orcaClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function makeSubmission(params: SubmissionParams): Promise<string | void> {
|
||||||
|
const { orcaClient, roundNumber, stakingKey, publicKey, secretKey } = params;
|
||||||
|
|
||||||
const swarmBountyId = await namespaceWrapper.storeGet(`swarmBountyId`);
|
const swarmBountyId = await namespaceWrapper.storeGet(`swarmBountyId`);
|
||||||
if (!swarmBountyId) {
|
if (!swarmBountyId) {
|
||||||
console.log("[SUBMISSION] No swarm bounty id found for this round");
|
console.log("[SUBMISSION] No swarm bounty id found for this round");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`[SUBMISSION] Fetching submission data for round ${roundNumber}. and submission roundnumber ${swarmBountyId}`);
|
|
||||||
|
const submissionData = await fetchSubmissionData(orcaClient, swarmBountyId);
|
||||||
|
if (!submissionData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await notifyMiddleServer({
|
||||||
|
taskId: TASK_ID!,
|
||||||
|
swarmBountyId,
|
||||||
|
prUrl: submissionData.prUrl,
|
||||||
|
stakingKey,
|
||||||
|
publicKey,
|
||||||
|
secretKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const signature = await signSubmissionPayload({
|
||||||
|
taskId: TASK_ID,
|
||||||
|
roundNumber,
|
||||||
|
stakingKey,
|
||||||
|
pubKey: publicKey,
|
||||||
|
...submissionData
|
||||||
|
}, secretKey);
|
||||||
|
|
||||||
|
const cid = await storeSubmissionOnIPFS(signature);
|
||||||
|
await cleanupSubmissionState();
|
||||||
|
|
||||||
|
return cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchSubmissionData(orcaClient: any, swarmBountyId: string): Promise<SubmissionData | null> {
|
||||||
|
console.log(`[SUBMISSION] Fetching submission data for swarm bounty ${swarmBountyId}`);
|
||||||
const result = await orcaClient.podCall(`submission/${swarmBountyId}`);
|
const result = await orcaClient.podCall(`submission/${swarmBountyId}`);
|
||||||
let submission;
|
|
||||||
console.log("[SUBMISSION] Submission result:", result);
|
|
||||||
console.log("[SUBMISSION] Submission result data:", result.data);
|
|
||||||
|
|
||||||
if (!result || result.data === "No submission") {
|
if (!result || result.data === "No submission") {
|
||||||
console.log("[SUBMISSION] No existing submission found");
|
console.log("[SUBMISSION] No existing submission found");
|
||||||
return;
|
return null;
|
||||||
} else {
|
|
||||||
// Add extra error handling for https://koii-workspace.slack.com/archives/C0886H01JM8/p1746137232538419
|
|
||||||
if (typeof result.data === 'object' && 'data' in result.data) {
|
|
||||||
console.log("[SUBMISSION] Submission result data is an object with 'data' property");
|
|
||||||
submission = result.data.data;
|
|
||||||
} else {
|
|
||||||
console.log("[SUBMISSION] Submission result data is not an object with 'data' property");
|
|
||||||
submission = result.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!submission.prUrl) {
|
const submission = typeof result.data === 'object' && 'data' in result.data
|
||||||
console.error("[SUBMISSION] Missing PR URL in submission");
|
? result.data.data
|
||||||
|
: result.data;
|
||||||
|
|
||||||
|
if (!submission?.prUrl) {
|
||||||
throw new Error("Submission is missing PR URL");
|
throw new Error("Submission is missing PR URL");
|
||||||
}
|
}
|
||||||
const middleServerPayload = {
|
|
||||||
taskId: TASK_ID,
|
return submission as SubmissionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function notifyMiddleServer(params: {
|
||||||
|
taskId: string;
|
||||||
|
swarmBountyId: string;
|
||||||
|
prUrl: string;
|
||||||
|
stakingKey: string;
|
||||||
|
publicKey: string;
|
||||||
|
secretKey: Uint8Array<ArrayBufferLike>;
|
||||||
|
}) {
|
||||||
|
const { taskId, swarmBountyId, prUrl, stakingKey, publicKey, secretKey } = params;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
taskId,
|
||||||
swarmBountyId,
|
swarmBountyId,
|
||||||
prUrl: submission.prUrl,
|
prUrl,
|
||||||
stakingKey,
|
stakingKey,
|
||||||
publicKey,
|
publicKey,
|
||||||
action: "add-round-number",
|
action: "add-round-number",
|
||||||
};
|
};
|
||||||
|
|
||||||
const middleServerSignature = await namespaceWrapper.payloadSigning(middleServerPayload, secretKey);
|
const signature = await namespaceWrapper.payloadSigning(payload, secretKey);
|
||||||
const middleServerResponse = await fetch(`${middleServerUrl}/summarizer/worker/add-round-number`, {
|
const response = await fetch(`${middleServerUrl}/summarizer/worker/add-round-number`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: { "Content-Type": "application/json" },
|
||||||
"Content-Type": "application/json",
|
body: JSON.stringify({ signature, stakingKey }),
|
||||||
},
|
|
||||||
body: JSON.stringify({ signature: middleServerSignature, stakingKey: stakingKey }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("[TASK] Add PR Response: ", middleServerResponse);
|
console.log("[TASK] Add PR Response: ", response);
|
||||||
|
|
||||||
if (middleServerResponse.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error(`Posting to middle server failed: ${middleServerResponse.statusText}`);
|
throw new Error(`Posting to middle server failed: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
const signature = await namespaceWrapper.payloadSigning(
|
}
|
||||||
{
|
|
||||||
taskId: TASK_ID,
|
|
||||||
roundNumber,
|
|
||||||
stakingKey,
|
|
||||||
pubKey:publicKey,
|
|
||||||
// action: "audit",
|
|
||||||
...submission,
|
|
||||||
},
|
|
||||||
secretKey,
|
|
||||||
);
|
|
||||||
console.log("[SUBMISSION] Payload signed successfully");
|
|
||||||
|
|
||||||
|
async function signSubmissionPayload(payload: any, secretKey: Uint8Array<ArrayBufferLike>): Promise<string> {
|
||||||
|
console.log("[SUBMISSION] Signing submission payload...");
|
||||||
|
const signature = await namespaceWrapper.payloadSigning(payload, secretKey);
|
||||||
|
console.log("[SUBMISSION] Payload signed successfully");
|
||||||
|
return signature!;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storeSubmissionOnIPFS(signature: string): Promise<string> {
|
||||||
console.log("[SUBMISSION] Storing submission on IPFS...");
|
console.log("[SUBMISSION] Storing submission on IPFS...");
|
||||||
const cid = await storeFile({ signature }, "submission.json");
|
const cid = await storeFile({ signature }, "submission.json");
|
||||||
|
if (!cid) {
|
||||||
|
throw new Error("Failed to store submission on IPFS");
|
||||||
|
}
|
||||||
console.log("[SUBMISSION] Submission stored successfully. CID:", cid);
|
console.log("[SUBMISSION] Submission stored successfully. CID:", cid);
|
||||||
// If done please set the shouldMakeSubmission to false
|
|
||||||
await namespaceWrapper.storeSet(`shouldMakeSubmission`, "false");
|
|
||||||
await namespaceWrapper.storeSet(`swarmBountyId`, "");
|
|
||||||
return cid;
|
return cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function cleanupSubmissionState(): Promise<void> {
|
||||||
|
await namespaceWrapper.storeSet(`shouldMakeSubmission`, "false");
|
||||||
|
await namespaceWrapper.storeSet(`swarmBountyId`, "");
|
||||||
|
}
|
36
worker/src/utils/check/anthropicCheck.ts
Normal file
36
worker/src/utils/check/anthropicCheck.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export function isValidAnthropicApiKey(key: string) {
|
||||||
|
const regex = /^sk-ant-[a-zA-Z0-9_-]{32,}$/;
|
||||||
|
return regex.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkAnthropicAPIKey(apiKey: string) {
|
||||||
|
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'x-api-key': apiKey,
|
||||||
|
'anthropic-version': '2023-06-01',
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'claude-3-opus-20240229', // or a cheaper model
|
||||||
|
max_tokens: 1, // minimal usage
|
||||||
|
messages: [{ role: 'user', content: 'Hi' }],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log('✅ API key is valid and has credit.');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
const data = await response.json().catch(() => ({}));
|
||||||
|
if (response.status === 401) {
|
||||||
|
console.log('❌ Invalid API key.');
|
||||||
|
} else if (response.status === 403 && data.error?.message?.includes('billing')) {
|
||||||
|
console.log('❌ API key has no credit or is not authorized.');
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ Unexpected error:', data);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
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;
|
|
||||||
// }
|
|
||||||
}
|
|
109
worker/src/utils/task/task.ts
Normal file
109
worker/src/utils/task/task.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// import { namespaceWrapper } from "@_koii/namespace-wrapper";
|
||||||
|
|
||||||
|
import { getOrcaClient } from "@_koii/task-manager/extensions";
|
||||||
|
import { actionMessage, errorMessage, middleServerUrl } from "../constant";
|
||||||
|
|
||||||
|
import { TASK_ID, namespaceWrapper } from "@_koii/namespace-wrapper";
|
||||||
|
import { LogLevel } from "@_koii/namespace-wrapper/dist/types";
|
||||||
|
export async function task(){
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
let requiredWorkResponse;
|
||||||
|
const orcaClient = await getOrcaClient();
|
||||||
|
// check if the env variable is valid
|
||||||
|
const stakingKeypair = await namespaceWrapper.getSubmitterAccount()!;
|
||||||
|
const pubKey = await namespaceWrapper.getMainAccountPubkey();
|
||||||
|
if (!orcaClient || !stakingKeypair || !pubKey) {
|
||||||
|
await namespaceWrapper.logMessage(LogLevel.Error, errorMessage.NO_ORCA_CLIENT, actionMessage.NO_ORCA_CLIENT);
|
||||||
|
// Wait for 1 minute before retrying
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 60000));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const stakingKey = stakingKeypair.publicKey.toBase58();
|
||||||
|
|
||||||
|
/****************** All these issues need to be generate a markdown file ******************/
|
||||||
|
|
||||||
|
const signature = await namespaceWrapper.payloadSigning(
|
||||||
|
{
|
||||||
|
taskId: TASK_ID,
|
||||||
|
// roundNumber: roundNumber,
|
||||||
|
action: "fetch-todo",
|
||||||
|
githubUsername: stakingKey,
|
||||||
|
stakingKey: stakingKey,
|
||||||
|
},
|
||||||
|
stakingKeypair.secretKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
const retryDelay = 10000; // 10 seconds in milliseconds
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
requiredWorkResponse = await fetch(`${middleServerUrl}/summarizer/worker/fetch-todo`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ signature: signature, stakingKey: stakingKey }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (requiredWorkResponse.status === 200) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[TASK] Server returned status ${requiredWorkResponse.status}, retrying in ${retryDelay/1000} seconds...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the response is 200 after all retries
|
||||||
|
if (!requiredWorkResponse || requiredWorkResponse.status !== 200) {
|
||||||
|
// await namespaceWrapper.storeSet(`result-${roundNumber}`, status.NO_ISSUES_PENDING_TO_BE_SUMMARIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const requiredWorkResponseData = await requiredWorkResponse.json();
|
||||||
|
console.log("[TASK] requiredWorkResponseData: ", requiredWorkResponseData);
|
||||||
|
// const uuid = uuidv4();
|
||||||
|
const alreadyAssigned = await namespaceWrapper.storeGet(JSON.stringify(requiredWorkResponseData.data.id));
|
||||||
|
if (alreadyAssigned) {
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
await namespaceWrapper.storeSet(JSON.stringify(requiredWorkResponseData.data.id), "initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const podcallPayload = {
|
||||||
|
taskId: TASK_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const podCallSignature = await namespaceWrapper.payloadSigning(podcallPayload, stakingKeypair.secretKey);
|
||||||
|
|
||||||
|
const jsonBody = {
|
||||||
|
task_id: TASK_ID,
|
||||||
|
swarmBountyId: requiredWorkResponseData.data.id,
|
||||||
|
repo_url: `https://github.com/${requiredWorkResponseData.data.repo_owner}/${requiredWorkResponseData.data.repo_name}`,
|
||||||
|
podcall_signature: podCallSignature,
|
||||||
|
};
|
||||||
|
console.log("[TASK] jsonBody: ", jsonBody);
|
||||||
|
try {
|
||||||
|
const repoSummaryResponse = await orcaClient.podCall(`worker-task`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(jsonBody),
|
||||||
|
});
|
||||||
|
console.log("[TASK] repoSummaryResponse: ", repoSummaryResponse);
|
||||||
|
if (repoSummaryResponse.status !== 200) {
|
||||||
|
// await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// await namespaceWrapper.storeSet(`result-${roundNumber}`, status.ISSUE_SUMMARIZATION_FAILED);
|
||||||
|
console.error("[TASK] EXECUTE TASK ERROR:", error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[TASK] EXECUTE TASK ERROR:", error);
|
||||||
|
// Wait for 1 minute before retrying on error
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for 1 minute before starting the next iteration
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 60000));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user