-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Allora Network machine learning (#149)
* Add Allora Network machine learning * Allora plugin PR feedback
- Loading branch information
1 parent
578b310
commit 07ca203
Showing
16 changed files
with
404 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
OPENAI_API_KEY= | ||
WALLET_PRIVATE_KEY= | ||
ALLORA_API_URL= | ||
ALLORA_API_KEY= | ||
COINGECKO_API_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Vercel AI Allora Example | ||
|
||
## Setup | ||
|
||
Copy the `.env.template` and populate with your values. | ||
|
||
``` | ||
cp .env.template .env | ||
``` | ||
|
||
## Usage | ||
|
||
``` | ||
npx ts-node index.ts | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { openai } from '@ai-sdk/openai' | ||
import { generateText } from 'ai' | ||
|
||
import { http, createWalletClient } from 'viem' | ||
import { privateKeyToAccount } from 'viem/accounts' | ||
import { sepolia } from 'viem/chains' | ||
|
||
import { getOnChainTools } from '@goat-sdk/adapter-vercel-ai' | ||
|
||
import { allora } from '@goat-sdk/plugin-allora' | ||
import { coingecko } from "@goat-sdk/plugin-coingecko" | ||
import { viem } from '@goat-sdk/wallet-viem' | ||
|
||
require('dotenv').config() | ||
|
||
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`) | ||
|
||
const walletClient = createWalletClient({ | ||
account: account, | ||
transport: http(), | ||
chain: sepolia, | ||
}) | ||
|
||
;(async () => { | ||
const tools = await getOnChainTools({ | ||
wallet: viem(walletClient), | ||
plugins: [ | ||
allora({ | ||
apiKey: process.env.ALLORA_API_KEY, | ||
}), | ||
coingecko({ | ||
apiKey: process.env.COINGECKO_API_KEY as string, | ||
}), | ||
], | ||
}) | ||
|
||
const result = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: tools, | ||
maxSteps: 5, | ||
prompt: 'Can you fetch the current price of ETH and the predicted price in 8 hours and make a recommendation as to whether I should buy or sell?', | ||
}) | ||
|
||
console.log(result.text) | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "goat-examples-vercel-ai-allora", | ||
"version": "0.1.0", | ||
"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-allora": "workspace:*", | ||
"@goat-sdk/plugin-coingecko": "workspace:*", | ||
"@goat-sdk/wallet-viem": "workspace:*", | ||
"ai": "catalog:", | ||
"dotenv": "^16.4.5", | ||
"viem": "2.21.49" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"extends": "../../../tsconfig.base.json", | ||
"compilerOptions": { | ||
"outDir": "dist" | ||
}, | ||
"include": ["index.ts"], | ||
"exclude": ["node_modules", "dist"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Goat Allora Plugin 🐐 (TypeScript) | ||
|
||
[Allora Network](https://allora.network) plugin for Goat. Allora Network is an AI-powered inference platform that delivers real-time, self-improving predictions and insights for various use cases. By aggregating and analyzing data from diverse sources—such as blockchain networks and off-chain APIs—Allora seamlessly provides low-latency, high-performance predictive analytics without requiring complex infrastructure. The platform’s intuitive approach allows developers to focus on building intelligence-driven solutions, while Allora takes care of the heavy lifting behind the scenes. | ||
|
||
## Installation | ||
|
||
``` | ||
npm install @goat-sdk/plugin-allora | ||
``` | ||
|
||
## Setup | ||
|
||
```typescript | ||
import { allora } from '@goat-sdk/plugin-allora' | ||
|
||
const plugin = allora({ | ||
apiKey: process.env.ALLORA_API_KEY, | ||
}) | ||
``` | ||
|
||
## Available Actions | ||
|
||
### Fetch Price Prediction | ||
|
||
Fetches a price prediction for the given asset and timeframe. | ||
|
||
## Goat | ||
|
||
<div align="center"> | ||
Go out and eat some grass. | ||
|
||
[Docs](https://ohmygoat.dev) | [Examples](https://github.com/goat-sdk/goat/tree/main/typescript/examples) | [Discord](https://discord.gg/goat-sdk)</div> | ||
|
||
## Goat 🐐 | ||
|
||
Goat 🐐 (Great On-chain Agent Toolkit) is an open-source library enabling AI agents to interact with blockchain protocols and smart contracts via their own wallets. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "@goat-sdk/plugin-allora", | ||
"version": "0.1.0", | ||
"files": [ | ||
"dist/**/*", | ||
"README.md", | ||
"package.json" | ||
], | ||
"scripts": { | ||
"build": "tsup", | ||
"clean": "rm -rf dist", | ||
"test": "vitest run --passWithNoTests" | ||
}, | ||
"sideEffects": false, | ||
"main": "./dist/index.js", | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"dependencies": { | ||
"@goat-sdk/core": "workspace:*", | ||
"zod": "catalog:", | ||
"axios": "1.7.9" | ||
}, | ||
"peerDependencies": { | ||
"@goat-sdk/core": "workspace:*" | ||
}, | ||
"homepage": "https://ohmygoat.dev", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/goat-sdk/goat.git" | ||
}, | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/goat-sdk/goat/issues" | ||
}, | ||
"keywords": [ | ||
"ai", | ||
"agents", | ||
"web3", | ||
"allora" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { PluginBase } from '@goat-sdk/core' | ||
import { AlloraService } from './allora.service' | ||
|
||
export interface AlloraPluginOptions { | ||
apiKey?: string | ||
apiRoot?: string | ||
} | ||
|
||
export class AlloraPlugin extends PluginBase { | ||
constructor(opts: AlloraPluginOptions) { | ||
super('allora', [ new AlloraService(opts) ]) | ||
} | ||
|
||
supportsChain = () => true | ||
} | ||
|
||
export function allora(options: AlloraPluginOptions) { | ||
return new AlloraPlugin(options) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Tool } from '@goat-sdk/core' | ||
import { AlloraAPIClient, AlloraPricePredictionToken, AlloraPricePredictionTimeframe } from './api' | ||
import { GetAlloraPricePredictionParameters } from './parameters' | ||
|
||
export interface AlloraServiceOptions { | ||
apiKey?: string | ||
apiRoot?: string | ||
} | ||
|
||
export class AlloraService { | ||
private readonly client: AlloraAPIClient | ||
|
||
constructor(opts: AlloraServiceOptions) { | ||
this.client = new AlloraAPIClient(opts) | ||
} | ||
|
||
@Tool({ | ||
description: 'Fetch a future price prediction for a crypto asset from Allora Network. Specify 5 minutes from now `5m`, or 8 hours from now `8h`.', | ||
}) | ||
async getPricePrediction(parameters: GetAlloraPricePredictionParameters) { | ||
const { ticker, timeframe } = parameters | ||
return this.client.fetchAlloraPricePrediction(ticker as AlloraPricePredictionToken, timeframe as AlloraPricePredictionTimeframe) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import axios from 'axios' | ||
|
||
export interface AlloraInferenceData { | ||
network_inference: string | ||
network_inference_normalized: string | ||
confidence_interval_percentiles: string[] | ||
confidence_interval_percentiles_normalized: string[] | ||
confidence_interval_values: string[] | ||
confidence_interval_values_normalized: string[] | ||
topic_id: string | ||
timestamp: number | ||
extra_data: string | ||
} | ||
|
||
export interface AlloraAPIResponse { | ||
request_id: string | ||
status: boolean | ||
data: { | ||
signature: string | ||
inference_data: AlloraInferenceData | ||
} | ||
} | ||
|
||
export enum AlloraPricePredictionToken { | ||
BTC = 'BTC', | ||
ETH = 'ETH', | ||
} | ||
|
||
export enum AlloraPricePredictionTimeframe { | ||
'5m' = '5m', | ||
'8h' = '8h', | ||
} | ||
|
||
export enum AlloraPricePredictionSignatureFormat { | ||
EthereumSepolia = 'ethereum-11155111' | ||
} | ||
|
||
export interface AlloraAPIClientOptions { | ||
apiKey?: string | ||
apiRoot?: string | ||
} | ||
|
||
export class AlloraAPIClient { | ||
private apiKey: string | null | undefined | ||
private apiRoot: string | ||
|
||
constructor(opts: AlloraAPIClientOptions) { | ||
this.apiKey = opts.apiKey | ||
|
||
opts.apiRoot = opts.apiRoot || 'https://api.upshot.xyz/v2/allora' | ||
this.apiRoot = opts.apiRoot[opts.apiRoot.length - 1] === '/' ? opts.apiRoot.substr(0, opts.apiRoot.length - 1) : opts.apiRoot | ||
} | ||
|
||
public async fetchAlloraPricePrediction( | ||
asset: AlloraPricePredictionToken, | ||
timeframe: AlloraPricePredictionTimeframe, | ||
signatureFormat: AlloraPricePredictionSignatureFormat = AlloraPricePredictionSignatureFormat.EthereumSepolia, | ||
): Promise<Partial<AlloraInferenceData>> { | ||
const url = `consumer/price/${signatureFormat}/${asset}/${timeframe}` | ||
const resp = await this.fetchAlloraAPIData(url) | ||
if (!resp?.data?.inference_data) { | ||
throw new Error(`API response missing data: ${JSON.stringify(resp)}`) | ||
} | ||
return resp.data.inference_data | ||
} | ||
|
||
private async fetchAlloraAPIData(endpoint: string): Promise<Partial<AlloraAPIResponse>> { | ||
endpoint = endpoint[0] === '/' ? endpoint.substr(1) : endpoint | ||
|
||
const url = `${this.apiRoot}/${endpoint}` | ||
const headers: Record<string, string> = { | ||
'Content-Type': 'application/json', | ||
'Accept': 'application/json', | ||
} | ||
if (!!this.apiKey) { | ||
headers['x-api-key'] = this.apiKey | ||
} | ||
|
||
const response = await axios.get(url, { headers }) | ||
if (response.status >= 400) { | ||
throw new Error(`Allora plugin: error requesting price prediction: url=${url} status=${response.status} body=${JSON.stringify(response.data, null, 4)}`) | ||
} | ||
|
||
return response.data | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './allora.plugin' | ||
export * from './parameters' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { createToolParameters } from '@goat-sdk/core' | ||
import { z } from 'zod' | ||
|
||
export class GetAlloraPricePredictionParameters extends createToolParameters( | ||
z.object({ | ||
ticker: z.enum(['BTC', 'ETH']).describe('The ticker of the currency for which to fetch a price prediction.'), | ||
timeframe: z.enum(['5m', '8h']).describe('The timeframe for the prediction (currently, either "5m" or "8h").'), | ||
}) | ||
) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/tsconfig", | ||
"extends": "../../../tsconfig.base.json", | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules", "dist"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { defineConfig } from 'tsup' | ||
import { treeShakableConfig } from '../../../tsup.config.base' | ||
|
||
export default defineConfig({ | ||
...treeShakableConfig, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"$schema": "https://turbo.build/schema.json", | ||
"extends": ["//"], | ||
"tasks": { | ||
"build": { | ||
"inputs": ["src/**", "tsup.config.ts", "!./**/*.test.{ts,tsx}", "tsconfig.json"], | ||
"dependsOn": ["^build"], | ||
"outputs": ["dist/**"] | ||
} | ||
} | ||
} |
Oops, something went wrong.