Skip to content
Open
18 changes: 14 additions & 4 deletions examples/acp_base/external_evaluation/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
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>
BUYER_ENTITY_ID=<buyer-entity-id>
BUYER_GAME_TWITTER_BEARER_TOKEN=<buyer-game-twitter-bearer-token>

SELLER_WALLET_PRIVATE_KEY=0x-<seller-wallet-private-key>
SELLER_AGENT_WALLET_ADDRESS=<seller-wallet-address>
SELLER_ENTITY_ID=<seller-entity-id>
SELLER_GAME_TWITTER_BEARER_TOKEN=<seller-game-twitter-bearer-token>


EVALUATOR_WALLET_PRIVATE_KEY=0x-<evaluator-wallet-private-key>
EVALUATOR_AGENT_WALLET_ADDRESS=<evaluator-agent-wallet-address>
EVALUATOR_ENTITY_ID=<evaluator-entity-id>
EVALUATOR_GAME_TWITTER_BEARER_TOKEN=<evaluator-game-twitter-bearer-token>
100 changes: 53 additions & 47 deletions examples/acp_base/external_evaluation/buyer.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,63 @@
// 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,
BUYER_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: BUYER_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>"
);
// Pick one of the agents based on your criteria (in this example we just pick the second one)
const chosenAgent = relevantAgents[0];
// 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 as `0x${string}`
);

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();
72 changes: 59 additions & 13 deletions examples/acp_base/external_evaluation/env.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,68 @@
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 BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>(
"BUYER_AGENT_WALLET_ADDRESS"
);

export const BUYER_ENTITY_ID = parseInt(getEnvVar("BUYER_ENTITY_ID"));

export const BUYER_GAME_TWITTER_BEARER_TOKEN = getEnvVar<string>(
"BUYER_GAME_TWITTER_BEARER_TOKEN"
);

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

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

export const SELLER_ENTITY_ID = parseInt(getEnvVar("SELLER_ENTITY_ID"));

export const SELLER_GAME_TWITTER_BEARER_TOKEN = getEnvVar<string>(
"SELLER_GAME_TWITTER_BEARER_TOKEN"
);

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

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

export const EVALUATOR_ENTITY_ID = parseInt(getEnvVar("EVALUATOR_ENTITY_ID"));

export const EVALUATOR_GAME_TWITTER_BEARER_TOKEN = getEnvVar<string>(
"EVALUATOR_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,
SELLER_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: SELLER_GAME_TWITTER_BEARER_TOKEN,
}),
});
}

seller();
14 changes: 10 additions & 4 deletions examples/acp_base/self_evaluation/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
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>
BUYER_ENTITY_ID=<buyer-entity-id>
BUYER_GAME_TWITTER_BEARER_TOKEN=<game-twitter-bearer-token>


SELLER_WALLET_PRIVATE_KEY=0x-<seller-wallet-private-key>
SELLER_AGENT_WALLET_ADDRESS=<seller-wallet-address>
SELLER_ENTITY_ID=<seller-entity-id>
SELLER_GAME_TWITTER_BEARER_TOKEN=<game-twitter-bearer-token>
Loading