Skip to content

Feat/implement game twitter client for follow #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 10 additions & 4 deletions examples/acp_base/external_evaluation/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>
SELLER_AGENT_WALLET_ADDRESS=<seller-agent-wallet-address>
BUYER_WALLET_PRIVATE_KEY=0x-<buyer-wallet-private-key>
SELLER_WALLET_PRIVATE_KEY=0x-<seller-wallet-private-key>
EVALUATOR_WALLET_PRIVATE_KEY=0x-<evaluator-wallet-private-key>
BUYER_AGENT_WALLET_ADDRESS=<buyer-wallet-address>
SELLER_AGENT_WALLET_ADDRESS=<seller-wallet-address>
BUYER_ENTITY_ID=<buyer-entity-id>
SELLER_ENTITY_ID=<seller-entity-id>
GAME_TWITTER_BEARER_TOKEN=<game-twitter-bearer-token>
EVALUATOR_AGENT_WALLET_ADDRESS=<evaluator-agent-wallet-address>
EVALUATOR_ENTITY_ID=<evaluator-entity-id>

102 changes: 55 additions & 47 deletions examples/acp_base/external_evaluation/buyer.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,65 @@
// TODO: Point the imports to acp-node after publishing

import AcpClient, {
AcpContractClient,
AcpJobPhases,
AcpJob,
baseSepoliaAcpConfig
} from '@virtuals-protocol/acp-node';
import AcpClient, {
AcpContractClient,
AcpJobPhases,
AcpJob,
baseSepoliaAcpConfig,
} from "@virtuals-protocol/acp-node";
import {
BUYER_AGENT_WALLET_ADDRESS,
EVALUATOR_AGENT_WALLET_ADDRESS,
WHITELISTED_WALLET_ENTITY_ID,
WHITELISTED_WALLET_PRIVATE_KEY
BUYER_AGENT_WALLET_ADDRESS,
EVALUATOR_AGENT_WALLET_ADDRESS,
BUYER_ENTITY_ID,
GAME_TWITTER_BEARER_TOKEN,
BUYER_WALLET_PRIVATE_KEY,
} from "./env";

import { TwitterApi } from "@virtuals-protocol/game-twitter-node";
async function buyer() {
const acpClient = new AcpClient({
acpContractClient: await AcpContractClient.build(
WHITELISTED_WALLET_PRIVATE_KEY,
WHITELISTED_WALLET_ENTITY_ID,
BUYER_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onNewTask: async (job: AcpJob) => {
if (
job.phase === AcpJobPhases.NEGOTIATION &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
) {
console.log("Paying job", job);
await job.pay(job.price);
console.log(`Job ${job.id} paid`);
} else if (job.phase === AcpJobPhases.COMPLETED) {
console.log(`Job ${job.id} completed`);
}
},
});
const acpClient = new AcpClient({
acpContractClient: await AcpContractClient.build(
BUYER_WALLET_PRIVATE_KEY,
BUYER_ENTITY_ID,
BUYER_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onNewTask: async (job: AcpJob) => {
if (
job.phase === AcpJobPhases.NEGOTIATION &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
) {
console.log("Paying job", job);
await job.pay(job.price);
console.log(`Job ${job.id} paid`);
} else if (job.phase === AcpJobPhases.COMPLETED) {
console.log(`Job ${job.id} completed`);
}
},
gameTwitterClient: new TwitterApi({
gameTwitterAccessToken: GAME_TWITTER_BEARER_TOKEN,
}),
});

// Browse available agents based on a keyword and cluster name
const relevantAgents = await acpClient.browseAgents("<your-filter-agent-keyword>", "<your-cluster-name>");
console.log("Relevant seller agents: ", relevantAgents);
// Pick one of the agents based on your criteria (in this example we just pick the second one)
const chosenAgent = relevantAgents[1];
// Pick one of the service offerings based on your criteria (in this example we just pick the first one)
const chosenJobOffering = chosenAgent.offerings[0]
// Browse available agents based on a keyword and cluster name
const relevantAgents = await acpClient.browseAgents(
"<your-filter-agent-keyword>",
"<your-cluster-name>"
);
console.log("Relevant seller agents: ", relevantAgents);
// Pick one of the agents based on your criteria (in this example we just pick the second one)
const chosenAgent = relevantAgents[1];
// Pick one of the service offerings based on your criteria (in this example we just pick the first one)
const chosenJobOffering = chosenAgent.offerings[0];

const jobId = await chosenJobOffering.initiateJob(
// <your_schema_field> can be found in your ACP Visualiser's "Edit Service" pop-up.
// Reference: (./images/specify-requirement-toggle-switch.png)
{ "<your_schema_field>": "Help me to generate a flower meme." },
new Date(Date.now() + 1000 * 60 * 60 * 24),
EVALUATOR_AGENT_WALLET_ADDRESS,
chosenAgent.twitterHandle
);

const jobId = await chosenJobOffering.initiateJob(
// <your_schema_field> can be found in your ACP Visualiser's "Edit Service" pop-up.
// Reference: (./images/specify-requirement-toggle-switch.png)
{'<your_schema_field>': "Help me to generate a flower meme."},
EVALUATOR_AGENT_WALLET_ADDRESS,
new Date(Date.now() + 1000 * 60 * 60 * 24)
);

console.log(`Job ${jobId} initiated`);
console.log(`Job ${jobId} initiated`);
}

buyer();
58 changes: 45 additions & 13 deletions examples/acp_base/external_evaluation/env.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,54 @@
import dotenv from "dotenv";
import { Address } from "viem";

dotenv.config({ path: __dirname + '/.env' });
dotenv.config({ path: __dirname + "/.env" });

function getEnvVar<T extends string = string>(key: string, required = true): T {
const value = process.env[key];
if (required && (value === undefined || value === '')) {
throw new Error(`${key} is not defined or is empty in the .env file`);
}
return value as T;
const value = process.env[key];
if (required && (value === undefined || value === "")) {
throw new Error(`${key} is not defined or is empty in the .env file`);
}
return value as T;
}

export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar<Address>('WHITELISTED_WALLET_PRIVATE_KEY');
export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10);
export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('BUYER_AGENT_WALLET_ADDRESS');
export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('SELLER_AGENT_WALLET_ADDRESS');
export const EVALUATOR_AGENT_WALLET_ADDRESS = getEnvVar<Address>('EVALUATOR_AGENT_WALLET_ADDRESS');
export const BUYER_WALLET_PRIVATE_KEY = getEnvVar<Address>(
"BUYER_WALLET_PRIVATE_KEY"
);

if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) {
throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file');
export const SELLER_WALLET_PRIVATE_KEY = getEnvVar<Address>(
"SELLER_WALLET_PRIVATE_KEY"
);

export const EVALUATOR_WALLET_PRIVATE_KEY = getEnvVar<Address>(
"EVALUATOR_WALLET_PRIVATE_KEY"
);

export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>(
"BUYER_AGENT_WALLET_ADDRESS"
);
export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>(
"SELLER_AGENT_WALLET_ADDRESS"
);
export const EVALUATOR_AGENT_WALLET_ADDRESS = getEnvVar<Address>(
"EVALUATOR_AGENT_WALLET_ADDRESS"
);
export const BUYER_ENTITY_ID = parseInt(getEnvVar("BUYER_ENTITY_ID"));
export const SELLER_ENTITY_ID = parseInt(getEnvVar("SELLER_ENTITY_ID"));
export const EVALUATOR_ENTITY_ID = parseInt(getEnvVar("EVALUATOR_ENTITY_ID"));
export const GAME_TWITTER_BEARER_TOKEN = getEnvVar<string>(
"GAME_TWITTER_BEARER_TOKEN"
);

if (isNaN(BUYER_ENTITY_ID)) {
throw new Error("BUYER_ENTITY_ID must be a valid number in the .env file");
}

if (isNaN(SELLER_ENTITY_ID)) {
throw new Error("SELLER_ENTITY_ID must be a valid number in the .env file");
}

if (isNaN(EVALUATOR_ENTITY_ID)) {
throw new Error(
"EVALUATOR_ENTITY_ID must be a valid number in the .env file"
);
}
32 changes: 16 additions & 16 deletions examples/acp_base/external_evaluation/evaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ import AcpClient, {
baseSepoliaAcpConfig
} from '@virtuals-protocol/acp-node';
import {
EVALUATOR_AGENT_WALLET_ADDRESS,
WHITELISTED_WALLET_ENTITY_ID,
WHITELISTED_WALLET_PRIVATE_KEY
EVALUATOR_AGENT_WALLET_ADDRESS,
EVALUATOR_ENTITY_ID,
EVALUATOR_WALLET_PRIVATE_KEY,
} from "./env";

async function evaluator() {
new AcpClient({
acpContractClient: await AcpContractClient.build(
WHITELISTED_WALLET_PRIVATE_KEY,
WHITELISTED_WALLET_ENTITY_ID,
EVALUATOR_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onEvaluate: async (job: AcpJob) => {
console.log("Evaluation function called", job);
await job.evaluate(true, "Externally evaluated and approved");
console.log(`Job ${job.id} evaluated`);
},
});
new AcpClient({
acpContractClient: await AcpContractClient.build(
EVALUATOR_WALLET_PRIVATE_KEY,
EVALUATOR_ENTITY_ID,
EVALUATOR_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onEvaluate: async (job: AcpJob) => {
console.log("Evaluation function called", job);
await job.evaluate(true, "Externally evaluated and approved");
console.log(`Job ${job.id} evaluated`);
},
});
}

evaluator();
83 changes: 44 additions & 39 deletions examples/acp_base/external_evaluation/seller.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,52 @@
// TODO: Point the imports to acp-node after publishing
import AcpClient, {
AcpContractClient,
AcpJobPhases,
AcpJob,
baseSepoliaAcpConfig
} from '@virtuals-protocol/acp-node';
import AcpClient, {
AcpContractClient,
AcpJobPhases,
AcpJob,
baseSepoliaAcpConfig,
} from "@virtuals-protocol/acp-node";
import {
SELLER_AGENT_WALLET_ADDRESS,
WHITELISTED_WALLET_ENTITY_ID,
WHITELISTED_WALLET_PRIVATE_KEY
SELLER_AGENT_WALLET_ADDRESS,
SELLER_ENTITY_ID,
SELLER_WALLET_PRIVATE_KEY,
GAME_TWITTER_BEARER_TOKEN,
} from "./env";
import { TwitterApi } from "@virtuals-protocol/game-twitter-node";

async function seller() {
new AcpClient({
acpContractClient: await AcpContractClient.build(
WHITELISTED_WALLET_PRIVATE_KEY,
WHITELISTED_WALLET_ENTITY_ID,
SELLER_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onNewTask: async (job: AcpJob) => {
if (
job.phase === AcpJobPhases.REQUEST &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
) {
console.log("Responding to job", job);
await job.respond(true);
console.log(`Job ${job.id} responded`);
} else if (
job.phase === AcpJobPhases.TRANSACTION &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
) {
console.log("Delivering job", job);
await job.deliver(
JSON.stringify({
type: "url",
value: "https://example.com",
})
);
console.log(`Job ${job.id} delivered`);
}
},
});
new AcpClient({
acpContractClient: await AcpContractClient.build(
SELLER_WALLET_PRIVATE_KEY,
SELLER_ENTITY_ID,
SELLER_AGENT_WALLET_ADDRESS,
baseSepoliaAcpConfig
),
onNewTask: async (job: AcpJob) => {
if (
job.phase === AcpJobPhases.REQUEST &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
) {
console.log("Responding to job", job);
await job.respond(true);
console.log(`Job ${job.id} responded`);
} else if (
job.phase === AcpJobPhases.TRANSACTION &&
job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
) {
console.log("Delivering job", job);
await job.deliver(
JSON.stringify({
type: "url",
value: "https://example.com",
})
);
console.log(`Job ${job.id} delivered`);
}
},
gameTwitterClient: new TwitterApi({
gameTwitterAccessToken: GAME_TWITTER_BEARER_TOKEN,
}),
});
}

seller();
11 changes: 7 additions & 4 deletions examples/acp_base/self_evaluation/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>
SELLER_AGENT_WALLET_ADDRESS=<seller-agent-wallet-address>
BUYER_WALLET_PRIVATE_KEY=0x-<buyer-wallet-private-key>
BUYER_AGENT_WALLET_ADDRESS=<buyer-wallet-address>
SELLER_WALLET_PRIVATE_KEY=0x-<seller-wallet-private-key>
SELLER_AGENT_WALLET_ADDRESS=<seller-wallet-address>
BUYER_ENTITY_ID=<buyer-entity-id>
SELLER_ENTITY_ID=<seller-entity-id>
GAME_TWITTER_BEARER_TOKEN=<game-twitter-bearer-token>
Loading