diff --git a/.env.example b/.env.example index 90ba94cfa8a..d7fd806fa6d 100644 --- a/.env.example +++ b/.env.example @@ -131,3 +131,8 @@ ZEROG_FLOW_ADDRESS= # Coinbase Commerce COINBASE_COMMERCE_KEY= + +# TEE Configuration +DSTACK_SIMULATOR_ENDPOINT= +WALLET_SECRET_SALT=secret_salt + diff --git a/Dockerfile b/Dockerfile index 68f8051ce0c..d9ecc59b34b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,17 @@ -FROM node:23.3.0 -# Install pnpm globally -RUN npm install -g pnpm@9.4.0 +# Stage 1: Build dependencies in a temporary stage +FROM node:23.3.0 AS builder + +# Install required global dependencies +RUN apt-get update && apt-get install -y \ + python3 \ + build-essential \ + git \ + curl \ + sqlite3 && \ + apt-get clean \ + && npm install -g pnpm@9.4.0 -# Set the working directory +# Set working directory WORKDIR /app # Add configuration files and install dependencies @@ -11,20 +20,64 @@ ADD package.json /app/package.json ADD .npmrc /app/.npmrc ADD tsconfig.json /app/tsconfig.json ADD pnpm-lock.yaml /app/pnpm-lock.yaml -RUN pnpm i -# Add the documentation -ADD docs /app/docs -RUN pnpm i +# Install dependencies +RUN pnpm install -# Add the rest of the application code +# Copy source code +ADD docs /app/docs ADD packages /app/packages -RUN pnpm i - -# Add the environment variables ADD scripts /app/scripts ADD characters /app/characters -ADD .env /app/.env +ADD agent /app/agent + +# Add dependencies to workspace root +RUN pnpm add -w -D ts-node typescript @types/node + +WORKDIR /app/packages/agent + +# Add dependencies to the agent package specifically +RUN pnpm add -D ts-node typescript @types/node --filter "@ai16z/agent" + +WORKDIR /app/packages/core +RUN pnpm add -D ts-node typescript @types/node --filter "@ai16z/eliza" + +WORKDIR /app + +# Optional: build step if using TypeScript or other build process +RUN pnpm build + +# Stage 2: Production image +FROM node:23.3.0 + +# Install dependencies required for the final runtime +RUN apt-get update && apt-get install -y \ + python3 \ + build-essential \ + git \ + curl \ + sqlite3 && \ + apt-get clean \ + && npm install -g pnpm@9.4.0 + +# Set working directory +WORKDIR /app + +# Copy built files from the builder stage +COPY --from=builder /app /app + +# install playwright +RUN pnpm exec playwright install +RUN pnpm exec playwright install-deps + +# Expose application port if running a web server +EXPOSE 3000 + +# Add health check to ensure the app is running +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s CMD curl -f http://localhost:3000 || exit 1 + +# Set environment variables to configure runtime model settings +ENV NODE_ENV=production -# Command to run the container -CMD ["tail", "-f", "/dev/null"] \ No newline at end of file +# Default command to run the application +CMD ["pnpm", "start"] diff --git a/agent/package.json b/agent/package.json index bb97c65a896..95bf6593727 100644 --- a/agent/package.json +++ b/agent/package.json @@ -28,6 +28,7 @@ "@ai16z/plugin-solana": "workspace:*", "@ai16z/plugin-0g": "workspace:*", "@ai16z/plugin-starknet": "workspace:*", + "@ai16z/plugin-tee": "workspace:*", "@ai16z/plugin-coinbase": "workspace:*", "readline": "1.3.0", "ws": "8.18.0", diff --git a/agent/src/index.ts b/agent/src/index.ts index 70a62da6e85..ad460b925ac 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -32,6 +32,9 @@ import { import { confluxPlugin } from "@ai16z/plugin-conflux"; import { createNodePlugin } from "@ai16z/plugin-node"; import { solanaPlugin } from "@ai16z/plugin-solana"; +import { nodePlugin } from "@ai16z/plugin-node"; +import { teePlugin } from "@ai16z/plugin-tee"; + import Database from "better-sqlite3"; import fs from "fs"; import path from "path"; @@ -281,6 +284,7 @@ export function createAgent( ? coinbaseMassPaymentsPlugin : null, getSecret(character, "BUTTPLUG_API_KEY") ? buttplugPlugin : null, + getSecret(character, "WALLET_SECRET_SALT") ? teePlugin : null, ].filter(Boolean), providers: [], actions: [], diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000000..4d0758d668a --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,40 @@ +services: + tee: + command: ["pnpm", "start"] + image: hashwarlock/tee-agent:latest + stdin_open: true + tty: true + volumes: + - /var/run/tappd.sock:/var/run/tappd.sock + - tee:/app/packages/client-twitter/src/tweetcache + - tee:/app/db.sqlite + environment: + - OPENAI_API_KEY= + - REDPILL_API_KEY= + - ELEVENLABS_XI_API_KEY= + - ELEVENLABS_MODEL_ID=eleven_multilingual_v2 + - ELEVENLABS_VOICE_ID=21m00Tcm4TlvDq8ikWAM + - ELEVENLABS_VOICE_STABILITY=0.5 + - ELEVENLABS_VOICE_SIMILARITY_BOOST=0.9 + - ELEVENLABS_VOICE_STYLE=0.66 + - ELEVENLABS_VOICE_USE_SPEAKER_BOOST=false + - ELEVENLABS_OPTIMIZE_STREAMING_LATENCY=4 + - ELEVENLABS_OUTPUT_FORMAT=pcm_16000 + - TWITTER_DRY_RUN=false + - TWITTER_USERNAME= + - TWITTER_PASSWORD= + - TWITTER_EMAIL= + - X_SERVER_URL=https://api.red-pill.ai/v1 + - BIRDEYE_API_KEY= + - SOL_ADDRESS=So11111111111111111111111111111111111111112 + - SLIPPAGE=1 + - RPC_URL=https://api.mainnet-beta.solana.com + - HELIUS_API_KEY= + - SERVER_PORT=3000 + - WALLET_SECRET_SALT=secret_salt + ports: + - "3000:80" + restart: always + +volumes: + tee: diff --git a/packages/plugin-tee/.npmignore b/packages/plugin-tee/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-tee/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-tee/README.md b/packages/plugin-tee/README.md new file mode 100644 index 00000000000..917e3b93bf1 --- /dev/null +++ b/packages/plugin-tee/README.md @@ -0,0 +1,52 @@ +# Plugin TEE + +A plugin for handling Trusted Execution Environment (TEE) operations. + +## Providers + +This plugin includes several providers for handling different TEE-related operations. + +### DeriveKeyProvider + +The `DeriveKeyProvider` allows for secure key derivation within a TEE environment. + +#### Usage + +```typescript +import { DeriveKeyProvider } from "@ai16z/plugin-tee"; +// Initialize the provider +const provider = new DeriveKeyProvider(); +// Derive a key +try { + const keypair = await provider.deriveKey("/path/to/derive", "subject-identifier"); + // keypair can now be used for cryptographic operations +} catch (error) { + console.error("Key derivation failed:", error); +} +``` + +### RemoteAttestationProvider + +The `RemoteAttestationProvider` allows for generating a remote attestation within a TEE environment. + +#### Usage + +```typescript +const provider = new RemoteAttestationProvider(); + +try { + const attestation = await provider.generateAttestation("your-report-data"); + console.log("Attestation:", attestation); +} catch (error) { + console.error("Failed to generate attestation:", error); +} +``` + +### Configuration + +When using the provider through the runtime environment, ensure the following settings are configured: + +```env +DSTACK_SIMULATOR_ENDPOINT="your-endpoint-url" # Optional, for simulator purposes if testing on mac or windows +WALLET_SECRET_SALT=your-secret-salt // Required to single agent deployments +``` diff --git a/packages/plugin-tee/package.json b/packages/plugin-tee/package.json new file mode 100644 index 00000000000..c48002ab63c --- /dev/null +++ b/packages/plugin-tee/package.json @@ -0,0 +1,26 @@ +{ + "name": "@ai16z/plugin-tee", + "version": "0.1.3", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@ai16z/eliza": "workspace:*", + "@phala/dstack-sdk": "^0.1.4", + "@solana/web3.js": "1.95.4", + "@solana/spl-token": "0.4.9", + "bignumber": "1.1.0", + "bignumber.js": "9.1.2", + "bs58": "^6.0.0", + "node-cache": "5.1.2", + "pumpdotfun-sdk": "1.3.2", + "tsup": "^8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --watch" + }, + "peerDependencies": { + "whatwg-url": "7.1.0" + } +} diff --git a/packages/plugin-tee/src/index.ts b/packages/plugin-tee/src/index.ts new file mode 100644 index 00000000000..0a3c1e6adf4 --- /dev/null +++ b/packages/plugin-tee/src/index.ts @@ -0,0 +1,25 @@ +import { Plugin } from "@ai16z/eliza"; +import { remoteAttestationProvider } from "./providers/remoteAttestationProvider"; +import { deriveKeyProvider } from "./providers/deriveKeyProvider"; +import { walletProvider } from "./providers/walletProvider"; + +export const teePlugin: Plugin = { + name: "tee", + description: + "TEE plugin with actions to generate remote attestations and derive keys", + actions: [ + /* custom actions */ + ], + evaluators: [ + /* custom evaluators */ + ], + providers: [ + /* custom providers */ + remoteAttestationProvider, + deriveKeyProvider, + walletProvider, + ], + services: [ + /* custom services */ + ], +}; diff --git a/packages/plugin-tee/src/providers/deriveKeyProvider.ts b/packages/plugin-tee/src/providers/deriveKeyProvider.ts new file mode 100644 index 00000000000..0e7cf9ac833 --- /dev/null +++ b/packages/plugin-tee/src/providers/deriveKeyProvider.ts @@ -0,0 +1,69 @@ +import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; +import { Keypair } from "@solana/web3.js"; +import crypto from "crypto"; +import { TappdClient } from "@phala/dstack-sdk"; + +class DeriveKeyProvider { + private client: TappdClient; + + constructor(endpoint?: string) { + this.client = endpoint ? new TappdClient(endpoint) : new TappdClient(); + } + + async deriveKey(path: string, subject: string): Promise { + try { + if (!path || !subject) { + console.error("Path and Subject are required for key derivation"); + } + + console.log("Deriving Key in TEE..."); + const derivedKey = await this.client.deriveKey(path, subject); + const uint8ArrayDerivedKey = derivedKey.asUint8Array(); + + const hash = crypto.createHash("sha256"); + hash.update(uint8ArrayDerivedKey); + const seed = hash.digest(); + const seedArray = new Uint8Array(seed); + const keypair = Keypair.fromSeed(seedArray.slice(0, 32)); + + console.log("Key Derived Successfully!"); + return keypair; + } catch (error) { + console.error("Error deriving key:", error); + throw error; + } + } +} + +const deriveKeyProvider: Provider = { + get: async (runtime: IAgentRuntime, _message?: Memory, _state?: State) => { + const endpoint = runtime.getSetting("DSTACK_SIMULATOR_ENDPOINT"); + const provider = new DeriveKeyProvider(endpoint); + try { + // Validate wallet configuration + if (!runtime.getSetting("WALLET_SECRET_SALT")) { + console.error( + "Wallet secret salt is not configured in settings" + ); + return ""; + } + + let keypair: Keypair; + try { + const secretSalt = + runtime.getSetting("WALLET_SECRET_SALT") || "secret_salt"; + return await provider.deriveKey("/", secretSalt); + } catch (error) { + console.error("Error creating PublicKey:", error); + return ""; + } + + return keypair; + } catch (error) { + console.error("Error in derive key provider:", error.message); + return `Failed to fetch derive key information: ${error instanceof Error ? error.message : "Unknown error"}`; + } + }, +}; + +export { deriveKeyProvider, DeriveKeyProvider }; diff --git a/packages/plugin-tee/src/providers/remoteAttestationProvider.ts b/packages/plugin-tee/src/providers/remoteAttestationProvider.ts new file mode 100644 index 00000000000..d8076afcafb --- /dev/null +++ b/packages/plugin-tee/src/providers/remoteAttestationProvider.ts @@ -0,0 +1,41 @@ +import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; +import { TappdClient } from "@phala/dstack-sdk"; + +class RemoteAttestationProvider { + private client: TappdClient; + + constructor(endpoint?: string) { + this.client = endpoint ? new TappdClient(endpoint) : new TappdClient(); + } + + async generateAttestation(reportData: string): Promise { + try { + console.log("Generating remote attestation..."); + const tdxQuote = await this.client.tdxQuote(reportData); + console.log("Remote attestation generated successfully!"); + return JSON.stringify(tdxQuote); + } catch (error) { + console.error("Error generating remote attestation:", error); + return `Failed to generate TDX Quote: ${error instanceof Error ? error.message : "Unknown error"}`; + } + } +} + +// Keep the original provider for backwards compatibility +const remoteAttestationProvider: Provider = { + get: async (runtime: IAgentRuntime, _message: Memory, _state?: State) => { + const endpoint = runtime.getSetting("DSTACK_SIMULATOR_ENDPOINT"); + const provider = new RemoteAttestationProvider(endpoint); + const agentId = runtime.agentId; + + try { + const attestation = await provider.generateAttestation(agentId); + return `Your Agent's remote attestation is: ${attestation}`; + } catch (error) { + console.error("Error in remote attestation provider:", error); + return ""; + } + }, +}; + +export { remoteAttestationProvider, RemoteAttestationProvider }; diff --git a/packages/plugin-tee/src/providers/walletProvider.ts b/packages/plugin-tee/src/providers/walletProvider.ts new file mode 100644 index 00000000000..b6d355d702a --- /dev/null +++ b/packages/plugin-tee/src/providers/walletProvider.ts @@ -0,0 +1,310 @@ +import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza"; +import { Connection, Keypair, PublicKey } from "@solana/web3.js"; +import BigNumber from "bignumber.js"; +import NodeCache from "node-cache"; +import { deriveKeyProvider } from "./deriveKeyProvider"; +// Provider configuration +const PROVIDER_CONFIG = { + BIRDEYE_API: "https://public-api.birdeye.so", + MAX_RETRIES: 3, + RETRY_DELAY: 2000, + DEFAULT_RPC: "https://api.mainnet-beta.solana.com", + TOKEN_ADDRESSES: { + SOL: "So11111111111111111111111111111111111111112", + BTC: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", + ETH: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", + }, +}; + +export interface Item { + name: string; + address: string; + symbol: string; + decimals: number; + balance: string; + uiAmount: string; + priceUsd: string; + valueUsd: string; + valueSol?: string; +} + +interface WalletPortfolio { + totalUsd: string; + totalSol?: string; + items: Array; +} + +interface BirdEyePriceData { + data: { + [key: string]: { + price: number; + priceChange24h: number; + }; + }; +} + +interface Prices { + solana: { usd: string }; + bitcoin: { usd: string }; + ethereum: { usd: string }; +} + +export class WalletProvider { + private cache: NodeCache; + + constructor( + private connection: Connection, + private walletPublicKey: PublicKey + ) { + this.cache = new NodeCache({ stdTTL: 300 }); // Cache TTL set to 5 minutes + } + + private async fetchWithRetry( + runtime, + url: string, + options: RequestInit = {} + ): Promise { + let lastError: Error; + + for (let i = 0; i < PROVIDER_CONFIG.MAX_RETRIES; i++) { + try { + const apiKey = runtime.getSetting("BIRDEYE_API_KEY"); + const response = await fetch(url, { + ...options, + headers: { + Accept: "application/json", + "x-chain": "solana", + "X-API-KEY": apiKey || "", + ...options.headers, + }, + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `HTTP error! status: ${response.status}, message: ${errorText}` + ); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error(`Attempt ${i + 1} failed:`, error); + lastError = error; + if (i < PROVIDER_CONFIG.MAX_RETRIES - 1) { + const delay = PROVIDER_CONFIG.RETRY_DELAY * Math.pow(2, i); + await new Promise((resolve) => setTimeout(resolve, delay)); + continue; + } + } + } + + console.error( + "All attempts failed. Throwing the last error:", + lastError + ); + throw lastError; + } + + async fetchPortfolioValue(runtime): Promise { + try { + const cacheKey = `portfolio-${this.walletPublicKey.toBase58()}`; + const cachedValue = this.cache.get(cacheKey); + + if (cachedValue) { + console.log("Cache hit for fetchPortfolioValue"); + return cachedValue; + } + console.log("Cache miss for fetchPortfolioValue"); + + const walletData = await this.fetchWithRetry( + runtime, + `${PROVIDER_CONFIG.BIRDEYE_API}/v1/wallet/token_list?wallet=${this.walletPublicKey.toBase58()}` + ); + + if (!walletData?.success || !walletData?.data) { + console.error("No portfolio data available", walletData); + throw new Error("No portfolio data available"); + } + + const data = walletData.data; + const totalUsd = new BigNumber(data.totalUsd.toString()); + const prices = await this.fetchPrices(runtime); + const solPriceInUSD = new BigNumber(prices.solana.usd.toString()); + + const items = data.items.map((item: any) => ({ + ...item, + valueSol: new BigNumber(item.valueUsd || 0) + .div(solPriceInUSD) + .toFixed(6), + name: item.name || "Unknown", + symbol: item.symbol || "Unknown", + priceUsd: item.priceUsd || "0", + valueUsd: item.valueUsd || "0", + })); + + const totalSol = totalUsd.div(solPriceInUSD); + const portfolio = { + totalUsd: totalUsd.toString(), + totalSol: totalSol.toFixed(6), + items: items.sort((a, b) => + new BigNumber(b.valueUsd) + .minus(new BigNumber(a.valueUsd)) + .toNumber() + ), + }; + this.cache.set(cacheKey, portfolio); + return portfolio; + } catch (error) { + console.error("Error fetching portfolio:", error); + throw error; + } + } + + async fetchPrices(runtime): Promise { + try { + const cacheKey = "prices"; + const cachedValue = this.cache.get(cacheKey); + + if (cachedValue) { + console.log("Cache hit for fetchPrices"); + return cachedValue; + } + console.log("Cache miss for fetchPrices"); + + const { SOL, BTC, ETH } = PROVIDER_CONFIG.TOKEN_ADDRESSES; + const tokens = [SOL, BTC, ETH]; + const prices: Prices = { + solana: { usd: "0" }, + bitcoin: { usd: "0" }, + ethereum: { usd: "0" }, + }; + + for (const token of tokens) { + const response = await this.fetchWithRetry( + runtime, + `${PROVIDER_CONFIG.BIRDEYE_API}/defi/price?address=${token}`, + { + headers: { + "x-chain": "solana", + }, + } + ); + + if (response?.data?.value) { + const price = response.data.value.toString(); + prices[ + token === SOL + ? "solana" + : token === BTC + ? "bitcoin" + : "ethereum" + ].usd = price; + } else { + console.warn(`No price data available for token: ${token}`); + } + } + + this.cache.set(cacheKey, prices); + return prices; + } catch (error) { + console.error("Error fetching prices:", error); + throw error; + } + } + + formatPortfolio( + runtime, + portfolio: WalletPortfolio, + prices: Prices + ): string { + let output = `${runtime.character.description}\n`; + output += `Wallet Address: ${this.walletPublicKey.toBase58()}\n\n`; + + const totalUsdFormatted = new BigNumber(portfolio.totalUsd).toFixed(2); + const totalSolFormatted = portfolio.totalSol; + + output += `Total Value: $${totalUsdFormatted} (${totalSolFormatted} SOL)\n\n`; + output += "Token Balances:\n"; + + const nonZeroItems = portfolio.items.filter((item) => + new BigNumber(item.uiAmount).isGreaterThan(0) + ); + + if (nonZeroItems.length === 0) { + output += "No tokens found with non-zero balance\n"; + } else { + for (const item of nonZeroItems) { + const valueUsd = new BigNumber(item.valueUsd).toFixed(2); + output += `${item.name} (${item.symbol}): ${new BigNumber( + item.uiAmount + ).toFixed(6)} ($${valueUsd} | ${item.valueSol} SOL)\n`; + } + } + + output += "\nMarket Prices:\n"; + output += `SOL: $${new BigNumber(prices.solana.usd).toFixed(2)}\n`; + output += `BTC: $${new BigNumber(prices.bitcoin.usd).toFixed(2)}\n`; + output += `ETH: $${new BigNumber(prices.ethereum.usd).toFixed(2)}\n`; + + return output; + } + + async getFormattedPortfolio(runtime): Promise { + try { + const [portfolio, prices] = await Promise.all([ + this.fetchPortfolioValue(runtime), + this.fetchPrices(runtime), + ]); + + return this.formatPortfolio(runtime, portfolio, prices); + } catch (error) { + console.error("Error generating portfolio report:", error); + return "Unable to fetch wallet information. Please try again later."; + } + } +} + +const walletProvider: Provider = { + get: async ( + runtime: IAgentRuntime, + _message: Memory, + _state?: State + ): Promise => { + try { + // Validate wallet configuration + if (!runtime.getSetting("WALLET_SECRET_SALT")) { + console.error( + "Wallet secret salt is not configured in settings" + ); + return ""; + } + + let publicKey: PublicKey; + try { + const derivedKeyPair: Keypair = await deriveKeyProvider.get( + runtime, + _message, + _state + ); + publicKey = derivedKeyPair.publicKey; + console.log("Wallet Public Key: ", publicKey.toBase58()); + } catch (error) { + console.error("Error creating PublicKey:", error); + return ""; + } + + const connection = new Connection(PROVIDER_CONFIG.DEFAULT_RPC); + const provider = new WalletProvider(connection, publicKey); + + const porfolio = await provider.getFormattedPortfolio(runtime); + return porfolio; + } catch (error) { + console.error("Error in wallet provider:", error.message); + return `Failed to fetch wallet information: ${error instanceof Error ? error.message : "Unknown error"}`; + } + }, +}; + +// Module exports +export { walletProvider }; diff --git a/packages/plugin-tee/src/types/tee.ts b/packages/plugin-tee/src/types/tee.ts new file mode 100644 index 00000000000..0cda39740fb --- /dev/null +++ b/packages/plugin-tee/src/types/tee.ts @@ -0,0 +1,12 @@ +export interface DeriveKeyResponse { + key: string; + certificate_chain: string[]; + asUint8Array: (max_length?: number) => Uint8Array; +} + +export type Hex = `0x${string}`; + +export interface TdxQuoteResponse { + quote: Hex; + event_log: string; +} diff --git a/packages/plugin-tee/tsconfig.json b/packages/plugin-tee/tsconfig.json new file mode 100644 index 00000000000..7541efa69db --- /dev/null +++ b/packages/plugin-tee/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/plugin-tee/tsup.config.ts b/packages/plugin-tee/tsup.config.ts new file mode 100644 index 00000000000..b94c126be77 --- /dev/null +++ b/packages/plugin-tee/tsup.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + // Add other modules you want to externalize + "@phala/dstack-sdk", + "safe-buffer", + "base-x", + "bs58", + "borsh", + "@solana/buffer-layout", + "stream", + "buffer", + ], +}); diff --git a/scripts/build.sh b/scripts/build.sh index 349f7f28b2f..3fe7ff678a5 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -35,6 +35,7 @@ PACKAGES=( "plugin-bootstrap" "plugin-image-generation" "plugin-coinbase" + "plugin-tee" "client-auto" "client-direct" "client-discord" diff --git a/scripts/docker.sh b/scripts/docker.sh index 10de416b532..7dc291e26c7 100755 --- a/scripts/docker.sh +++ b/scripts/docker.sh @@ -44,6 +44,7 @@ case "$1" in "plugin-image-generation" "plugin-node" "plugin-solana" + "plugin-tee" ) # Start building the docker run command