Skip to content

Commit

Permalink
feat: Add support for GAME framework (#207)
Browse files Browse the repository at this point in the history
Add support for GAME framework
  • Loading branch information
0xaguspunk authored Jan 9, 2025
1 parent 30847af commit 1bd8b67
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 0 deletions.
4 changes: 4 additions & 0 deletions typescript/examples/virtuals-game/viem/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OPENAI_API_KEY=
WALLET_PRIVATE_KEY=
RPC_PROVIDER_URL=
VIRTUALS_GAME_API_KEY=
15 changes: 15 additions & 0 deletions typescript/examples/virtuals-game/viem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Vercel AI with viem Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
npx ts-node index.ts
```
90 changes: 90 additions & 0 deletions typescript/examples/virtuals-game/viem/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
ExecutableGameFunctionResponse,
ExecutableGameFunctionStatus,
GameAgent,
GameFunction,
GameWorker,
} from "@virtuals-protocol/game";

import { http } from "viem";
import { createWalletClient } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mode } from "viem/chains";

import { ToolBase, getTools } from "@goat-sdk/core";
import { PEPE, USDC, erc20 } from "@goat-sdk/plugin-erc20";
import { sendETH } from "@goat-sdk/wallet-evm";
import { viem } from "@goat-sdk/wallet-viem";
import type { JSONSchemaType } from "ajv";
import { zodToJsonSchema } from "zod-to-json-schema";

require("dotenv").config();

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);

const walletClient = createWalletClient({
account: account,
transport: http(process.env.RPC_PROVIDER_URL),
chain: mode,
});

(async () => {
const tools: ToolBase[] = await getTools({
wallet: viem(walletClient),
plugins: [sendETH(), erc20({ tokens: [USDC, PEPE] })],
});

const workerFunctions = tools.map((tool) => {
// biome-ignore lint/suspicious/noExplicitAny: Fix types later
const schema = zodToJsonSchema(tool.parameters as any, {
target: "jsonSchema7",
}) as JSONSchemaType<typeof tool.parameters>;

const properties = Object.keys(schema.properties);

const args = properties.map((property) => ({
name: property,
description: schema.properties[property].description ?? "",
}));

return new GameFunction({
name: tool.name,
description: tool.description,
args: args,
executable: async (args) => {
try {
const result = await tool.execute(args);
return new ExecutableGameFunctionResponse(
ExecutableGameFunctionStatus.Done,
JSON.stringify(result),
);
} catch (e) {
return new ExecutableGameFunctionResponse(
ExecutableGameFunctionStatus.Failed,
`Failed to execute tool: ${e}`,
);
}
},
});
});

const onChainWorker = new GameWorker({
id: "onchain_worker",
name: "Onchain worker",
description: "Worker that executes onchain actions",
functions: [...workerFunctions],
});

const agent = new GameAgent(process.env.VIRTUALS_GAME_API_KEY as string, {
name: "Onchain agent",
goal: "Swap 0.01 USDC to MODE",
description: "An agent that executes onchain actions",
workers: [onChainWorker],
});

await agent.init();

await agent.run(10, {
verbose: true,
});
})();
27 changes: 27 additions & 0 deletions typescript/examples/virtuals-game/viem/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "goat-examples-virtuals-game-viem",
"version": "0.2.7",
"description": "",
"private": true,
"scripts": {
"test": "vitest run --passWithNoTests"
},
"author": "",
"license": "MIT",
"dependencies": {
"@ai-sdk/openai": "^1.0.4",
"@goat-sdk/adapter-vercel-ai": "workspace:*",
"@goat-sdk/core": "workspace:*",
"@goat-sdk/plugin-erc20": "workspace:*",
"@goat-sdk/wallet-evm": "workspace:*",
"@goat-sdk/plugin-kim": "workspace:*",
"@goat-sdk/wallet-viem": "workspace:*",
"@virtuals-protocol/game": "0.1.4",
"ai": "4.0.27",
"ajv": "8.17.1",
"dotenv": "^16.4.5",
"viem": "2.21.49",
"zod": "catalog:",
"zod-to-json-schema": "3.24.1"
}
}
95 changes: 95 additions & 0 deletions typescript/examples/virtuals-game/viem/toolCalling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
ExecutableGameFunctionResponse,
ExecutableGameFunctionStatus,
GameAgent,
GameFunction,
GameWorker,
} from "@virtuals-protocol/game";

import { http } from "viem";
import { createWalletClient } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mode } from "viem/chains";

import { openai } from "@ai-sdk/openai";
import { getOnChainTools } from "@goat-sdk/adapter-vercel-ai";
import { MODE, PEPE, USDC, erc20 } from "@goat-sdk/plugin-erc20";
import { kim } from "@goat-sdk/plugin-kim";
import { sendETH } from "@goat-sdk/wallet-evm";
import { viem } from "@goat-sdk/wallet-viem";
import { generateText } from "ai";

require("dotenv").config();

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);

const walletClient = createWalletClient({
account: account,
transport: http(process.env.RPC_PROVIDER_URL),
chain: mode,
});

(async () => {
const tools = await getOnChainTools({
wallet: viem(walletClient),
plugins: [sendETH(), erc20({ tokens: [USDC, MODE] }), kim()],
});

const swap = new GameFunction({
name: "Swap tokens",
description: "Allows you to swap tokens",
args: [
{
name: "from",
description: "The token to swap from",
},
{
name: "to",
description: "The token to swap to",
},
{
name: "amount",
description: "The amount of tokens to swap",
},
],
executable: async (args) => {
try {
const result = await generateText({
model: openai("gpt-4o-mini"),
tools: tools,
maxSteps: 10,
prompt: `Swap tokens using Kim protocol in a single hop: ${JSON.stringify(args)}`,
onStepFinish: (event) => {
console.log(event.toolResults);
},
});
return new ExecutableGameFunctionResponse(ExecutableGameFunctionStatus.Done, result.text);
} catch (e) {
return new ExecutableGameFunctionResponse(
ExecutableGameFunctionStatus.Failed,
`Failed to execute tool: ${e}`,
);
}
},
});

const onChainWorker = new GameWorker({
id: "onchain_worker",
name: "Onchain worker",
description: "Worker that executes onchain actions",
functions: [swap],
});

const agent = new GameAgent(process.env.VIRTUALS_GAME_API_KEY as string, {
name: "Onchain agent",
goal: "Swap 0.01 USDC to MODE",
description: "An agent that executes onchain actions",
workers: [onChainWorker],
});

await agent.init();

await agent.run(10, {
verbose: true,
});
})();
8 changes: 8 additions & 0 deletions typescript/examples/virtuals-game/viem/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["index.ts", "toolCalling.ts"],
"exclude": ["node_modules", "dist"]
}
97 changes: 97 additions & 0 deletions typescript/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1bd8b67

Please sign in to comment.