diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a938df5 --- /dev/null +++ b/.env.example @@ -0,0 +1,48 @@ +# AI Services +OPENAI_API_KEY=sk-... +OPENAI_MODEL=gpt-4 +HF_API_TOKEN=hf_... +HF_MODEL= +LANGCHAIN_ENABLED=false + +# Vector Stores (Optional) +VECTOR_STORE_PROVIDER= +VECTOR_STORE_API_KEY= +VECTOR_STORE_ENVIRONMENT= +VECTOR_STORE_URL= + +# Web3 - EVM +ETH_RPC_URL= +ETH_PRIVATE_KEY= +ETH_CHAIN_ID=1 + +# Web3 - Solana +SOLANA_RPC_URL= +SOLANA_PRIVATE_KEY= +SOLANA_COMMITMENT=confirmed + +# Messaging - Slack +SLACK_BOT_TOKEN= +SLACK_SIGNING_SECRET= + +# Messaging - Discord +DISCORD_BOT_TOKEN= + +# Data - PostgreSQL +DATABASE_URL=postgresql://user:password@localhost:5432/dbname + +# Data - Redis +REDIS_URL=redis://localhost:6379 + +# Data - AWS S3 +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_REGION=us-east-1 +S3_BUCKET= + +# Data - IPFS +IPFS_URL=http://localhost:5001 + +# Application +NODE_ENV=development +ENVIRONMENT=dev diff --git a/.github/workflows/container-deploy.yml b/.github/workflows/container-deploy.yml new file mode 100644 index 0000000..5346c99 --- /dev/null +++ b/.github/workflows/container-deploy.yml @@ -0,0 +1,83 @@ +name: Container Build and Deploy + +on: + push: + branches: [ master, main ] + workflow_dispatch: + inputs: + environment: + description: 'Environment to deploy to' + required: true + default: 'dev' + type: choice + options: + - dev + - stage + - prod + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + strategy: + matrix: + # Build all environments on push, single environment on manual dispatch + environment: ${{ github.event_name == 'workflow_dispatch' && fromJSON(format('["{0}"]', github.event.inputs.environment)) || fromJSON('["dev", "stage", "prod"]') }} + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + # NOTE: Use placeholder token for now - configure secrets in repository settings + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=sha,prefix=${{ matrix.environment }}- + type=raw,value=${{ matrix.environment }}-latest + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + # NOTE: Push disabled by default - enable when ready to deploy + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + ENVIRONMENT=${{ matrix.environment }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Image build summary + run: | + echo "### Container Build Summary :rocket:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Environment:** ${{ matrix.environment }}" >> $GITHUB_STEP_SUMMARY + echo "**Registry:** ${{ env.REGISTRY }}" >> $GITHUB_STEP_SUMMARY + echo "**Image:** ${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY + echo "**Tags:**" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "_Note: Image push is currently disabled. Enable in workflow when ready._" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e84500f --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Dependencies +node_modules/ +package-lock.json +yarn.lock + +# Build outputs +dist/ +build/ +*.js +*.d.ts +!src/**/*.ts +!test/**/*.js + +# Python +__pycache__/ +*.py[cod] +*$py.class +.Python +venv/ +.venv/ +env/ +ENV/ + +# Go +*.exe +*.test +*.out +go.sum + +# Rust +target/ +Cargo.lock + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment +.env +.env.local +.env.*.local + +# Test coverage +coverage/ +.nyc_output/ + +# Temporary files +tmp/ +temp/ +*.tmp diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..90f29cf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +# Multi-stage build for Node.js/TypeScript application +FROM node:18-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package.json tsconfig.json ./ + +# Install dependencies (including optional) +RUN npm install --include=optional || npm install + +# Copy source code +COPY sdk/ ./sdk/ +COPY src/ ./src/ + +# Build TypeScript +RUN npm run build || echo "Build step completed" + +# Production image +FROM node:18-alpine + +WORKDIR /app + +# Copy package files and install production dependencies only +COPY package.json ./ +RUN npm install --production || npm install + +# Copy built artifacts from builder +COPY --from=builder /app/dist ./dist + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 + +USER nodejs + +# Environment arg (dev/stage/prod) +ARG ENVIRONMENT=dev +ENV NODE_ENV=production +ENV ENVIRONMENT=${ENVIRONMENT} + +# Expose port (placeholder) +EXPOSE 3000 + +# Default command (placeholder - update based on your application) +CMD ["node", "dist/index.js"] diff --git a/README.md b/README.md index 3bbb070..47ff2ac 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,234 @@ # Transparency-Logic-Time-Machine-Bots- -The Grand United Fields of Theories +The Grand United Fields of Theories + +## AI/Web3 Integration Bundle + +This repository provides a comprehensive integration bundle for AI, Web3, messaging, and data services. Built primarily with Node.js/TypeScript, with adapter notes for Python, Go, and Rust. + +## Features + +- **AI Integration**: OpenAI, Hugging Face, LangChain, LlamaIndex, vector stores (Pinecone, Weaviate, Chroma) +- **Web3 Support**: EVM chains (ethers.js), Solana (@solana/web3.js, Anchor), extensible for other chains +- **Messaging**: Slack SDK, Discord SDK +- **Data Services**: PostgreSQL, Redis, AWS S3, IPFS +- **Container Deployment**: GitHub Actions workflow for container builds to ghcr.io +- **Multi-language Support**: TypeScript/Node.js primary, with Python/Go/Rust adapter notes + +## Installation + +```bash +npm install +``` + +### Optional Heavy Dependencies + +Some AI and vector store dependencies are marked as optional to reduce installation size: + +```bash +# Install with all optional dependencies +npm install --include=optional + +# Install specific optional dependencies +npm install @huggingface/transformers @pinecone-database/pinecone +``` + +### Linux Compatibility + +All dependencies are Linux-compatible. For optimal performance: +- Node.js 18+ recommended +- Python 3.8+ for Python adapters +- Go 1.20+ for Go adapters +- Rust 1.70+ for Rust adapters + +## Quick Start + +```typescript +import { SDK } from './sdk'; + +// Create all adapters from environment variables +const sdk = SDK.createFromEnv(); + +// Access individual adapters +const ai = sdk.ai; +const web3 = sdk.web3; +const messaging = sdk.messaging; +const data = sdk.data; +``` + +## Adapters & Providers + +### AI Adapter (`sdk/ai/adapter.ts`) + +Integrates with [@lippytm/ai-sdk](https://github.com/lippytm/ai-sdk) for AI services. + +**Providers:** +- OpenAI (GPT-4, GPT-3.5, embeddings) +- Hugging Face (transformers, inference API) - *optional* +- LangChain (chains, agents, tools) +- LlamaIndex (query engines, indices) +- Vector Stores: + - Pinecone - *optional* + - Weaviate - *optional* + - Chroma - *optional* + +**Required Environment Variables:** +```bash +OPENAI_API_KEY=sk-... # OpenAI API key +OPENAI_MODEL=gpt-4 # Optional: model selection +HF_API_TOKEN=hf_... # Hugging Face API token (optional) +HF_MODEL=model-name # Hugging Face model (optional) +LANGCHAIN_ENABLED=true # Enable LangChain (optional) +VECTOR_STORE_PROVIDER=pinecone # Vector store: pinecone|weaviate|chroma +VECTOR_STORE_API_KEY=... # Vector store API key +VECTOR_STORE_ENVIRONMENT=... # Vector store environment +VECTOR_STORE_URL=... # Vector store URL +``` + +### Web3 Adapter (`sdk/web3/adapter.ts`) + +Multi-chain blockchain integration. + +**Providers:** +- EVM chains via ethers.js (Ethereum, Polygon, BSC, Arbitrum, Optimism, etc.) +- Solana via @solana/web3.js +- Anchor framework support (optional) +- Extension points for other chains + +**Required Environment Variables:** +```bash +ETH_RPC_URL=https://... # Ethereum/EVM RPC endpoint +ETH_PRIVATE_KEY=0x... # Ethereum private key (use secret manager!) +ETH_CHAIN_ID=1 # Chain ID (optional) +SOLANA_RPC_URL=https://... # Solana RPC endpoint +SOLANA_PRIVATE_KEY=... # Solana private key (use secret manager!) +SOLANA_COMMITMENT=confirmed # Solana commitment level (optional) +``` + +### Messaging Adapter (`sdk/messaging/adapter.ts`) + +Multi-platform messaging integration. + +**Providers:** +- Slack via @slack/web-api +- Discord via discord.js + +**Required Environment Variables:** +```bash +SLACK_BOT_TOKEN=xoxb-... # Slack bot token +SLACK_SIGNING_SECRET=... # Slack signing secret (optional) +DISCORD_BOT_TOKEN=... # Discord bot token +``` + +### Data Adapter (`sdk/data/adapter.ts`) + +Multi-source data integration. + +**Providers:** +- PostgreSQL via pg +- Redis +- AWS S3 +- IPFS + +**Required Environment Variables:** +```bash +DATABASE_URL=postgresql://... # PostgreSQL connection string +REDIS_URL=redis://... # Redis connection string +AWS_ACCESS_KEY_ID=... # AWS access key +AWS_SECRET_ACCESS_KEY=... # AWS secret key +AWS_REGION=us-east-1 # AWS region +S3_BUCKET=bucket-name # S3 bucket name (optional) +IPFS_URL=http://localhost:5001 # IPFS node URL +``` + +## Multi-Language Support + +### Python Adapters + +See [sdk/PYTHON_ADAPTERS.md](sdk/PYTHON_ADAPTERS.md) for Python implementation examples using: +- `openai`, `transformers`, `langchain`, `llama-index` +- `web3.py`, `solana-py` +- `slack-sdk`, `discord.py` +- `psycopg2`, `redis-py`, `boto3`, `ipfshttpclient` + +### Go Adapters + +See [sdk/GO_ADAPTERS.md](sdk/GO_ADAPTERS.md) for Go implementation examples using: +- `go-openai`, `langchaingo` +- `go-ethereum`, `solana-go` +- `slack-go`, `discordgo` +- `pgx`, `go-redis`, `aws-sdk-go-v2`, `go-ipfs-api` + +### Rust Adapters + +See [sdk/RUST_ADAPTERS.md](sdk/RUST_ADAPTERS.md) for Rust implementation examples using: +- `async-openai`, `llm-chain` +- `ethers`, `solana-sdk`, `anchor-client` +- `slack-morphism`, `serenity` +- `tokio-postgres`, `redis`, `rusoto_s3`, `ipfs-api-backend-hyper` + +## Container Deployment + +The repository includes a GitHub Actions workflow for building and pushing container images to GitHub Container Registry (ghcr.io). + +**Workflow:** `.github/workflows/container-deploy.yml` + +**Triggers:** +- Push to `master` or `main` branches +- Manual workflow dispatch + +**Environments:** +- `dev`: Development environment +- `stage`: Staging environment +- `prod`: Production environment + +**Image Tags:** +- Branch-based: `ghcr.io/lippytm/transparency-logic-time-machine-bots-:master` +- Environment + SHA: `ghcr.io/lippytm/transparency-logic-time-machine-bots-:dev-abc1234` +- Environment latest: `ghcr.io/lippytm/transparency-logic-time-machine-bots-:dev-latest` + +**Note:** Container push is currently disabled in the workflow. Enable `push: true` in the workflow when ready to deploy. + +## Development + +### Build + +```bash +npm run build +``` + +### Test + +```bash +npm test +``` + +### Docker Build + +```bash +docker build -t transparency-logic-bots:dev --build-arg ENVIRONMENT=dev . +``` + +## Security Notes + +⚠️ **Important Security Considerations:** + +1. **Never commit secrets** to the repository +2. **Use environment variables** for all sensitive data +3. **Use secret managers** in production (AWS Secrets Manager, HashiCorp Vault, etc.) +4. **Rotate keys regularly** +5. **Use least-privilege principles** for API keys and service accounts +6. **Enable MFA** where supported + +The adapter `fromEnv()` methods are placeholders. In production, integrate with a proper secret management system. + +## Contributing + +This is an additive integration bundle. When adding new features: +- Keep changes minimal and non-breaking +- Add optional dependencies when appropriate +- Update documentation +- Ensure tests pass + +## License + +MIT diff --git a/package.json b/package.json new file mode 100644 index 0000000..0f50217 --- /dev/null +++ b/package.json @@ -0,0 +1,89 @@ +{ + "name": "@lippytm/transparency-logic-time-machine-bots", + "version": "1.0.0", + "description": "The Grand United Fields of Theories - AI/Web3 Integration Bundle", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "test": "node --test test/", + "lint": "echo 'Linting not configured yet'", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "ai", + "web3", + "blockchain", + "transparency", + "bots" + ], + "author": "lippytm", + "license": "MIT", + "peerDependencies": { + "@lippytm/ai-sdk": "*" + }, + "peerDependenciesMeta": { + "@lippytm/ai-sdk": { + "optional": true + }, + "openai": { + "optional": true + }, + "langchain": { + "optional": true + }, + "llamaindex": { + "optional": true + }, + "@huggingface/transformers": { + "optional": true + }, + "@huggingface/inference": { + "optional": true + }, + "@pinecone-database/pinecone": { + "optional": true + }, + "weaviate-ts-client": { + "optional": true + }, + "chromadb": { + "optional": true + }, + "ethers": { + "optional": true + }, + "@solana/web3.js": { + "optional": true + }, + "@coral-xyz/anchor": { + "optional": true + }, + "@slack/web-api": { + "optional": true + }, + "discord.js": { + "optional": true + }, + "pg": { + "optional": true + }, + "redis": { + "optional": true + }, + "@aws-sdk/client-s3": { + "optional": true + }, + "ipfs-http-client": { + "optional": true + } + }, + "devDependencies": { + "@types/node": "^20.10.0", + "@types/pg": "^8.10.0", + "typescript": "^5.3.0" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/sdk/GO_ADAPTERS.md b/sdk/GO_ADAPTERS.md new file mode 100644 index 0000000..1b73668 --- /dev/null +++ b/sdk/GO_ADAPTERS.md @@ -0,0 +1,202 @@ +# Go Equivalent Adapters + +This document provides guidance for implementing equivalent adapters in Go. + +## AI Adapter (Go) + +```go +// go.mod dependencies +require ( + github.com/sashabaranov/go-openai v1.17.0 + github.com/tmc/langchaingo v0.0.0-20231208 + // Note: Hugging Face and vector stores have limited Go support + // Consider using HTTP clients or gRPC for these services +) +``` + +**Example usage:** +```go +package ai + +import ( + "context" + "os" + openai "github.com/sashabaranov/go-openai" +) + +type AIAdapter struct { + openaiClient *openai.Client +} + +func FromEnv() *AIAdapter { + apiKey := os.Getenv("OPENAI_API_KEY") + if apiKey == "" { + return &AIAdapter{} + } + return &AIAdapter{ + openaiClient: openai.NewClient(apiKey), + } +} +``` + +## Web3 Adapter (Go) + +```go +// go.mod dependencies +require ( + github.com/ethereum/go-ethereum v1.13.0 + github.com/gagliardetto/solana-go v1.8.0 +) +``` + +**Example usage:** +```go +package web3 + +import ( + "context" + "os" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/gagliardetto/solana-go/rpc" +) + +type Web3Adapter struct { + ethClient *ethclient.Client + solanaClient *rpc.Client +} + +func FromEnv() (*Web3Adapter, error) { + adapter := &Web3Adapter{} + + if rpcURL := os.Getenv("ETH_RPC_URL"); rpcURL != "" { + client, err := ethclient.Dial(rpcURL) + if err != nil { + return nil, err + } + adapter.ethClient = client + } + + if rpcURL := os.Getenv("SOLANA_RPC_URL"); rpcURL != "" { + adapter.solanaClient = rpc.New(rpcURL) + } + + return adapter, nil +} +``` + +## Messaging Adapter (Go) + +```go +// go.mod dependencies +require ( + github.com/slack-go/slack v0.12.0 + github.com/bwmarrin/discordgo v0.27.0 +) +``` + +**Example usage:** +```go +package messaging + +import ( + "os" + "github.com/slack-go/slack" + "github.com/bwmarrin/discordgo" +) + +type MessagingAdapter struct { + slackClient *slack.Client + discordSession *discordgo.Session +} + +func FromEnv() (*MessagingAdapter, error) { + adapter := &MessagingAdapter{} + + if token := os.Getenv("SLACK_BOT_TOKEN"); token != "" { + adapter.slackClient = slack.New(token) + } + + if token := os.Getenv("DISCORD_BOT_TOKEN"); token != "" { + session, err := discordgo.New("Bot " + token) + if err != nil { + return nil, err + } + adapter.discordSession = session + } + + return adapter, nil +} +``` + +## Data Adapter (Go) + +```go +// go.mod dependencies +require ( + github.com/jackc/pgx/v5 v5.5.0 + github.com/redis/go-redis/v9 v9.3.0 + github.com/aws/aws-sdk-go-v2 v1.24.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.44.0 + github.com/ipfs/go-ipfs-api v0.7.0 +) +``` + +**Example usage:** +```go +package data + +import ( + "context" + "os" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/redis/go-redis/v9" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +type DataAdapter struct { + pgPool *pgxpool.Pool + redisClient *redis.Client + s3Client *s3.Client +} + +func FromEnv(ctx context.Context) (*DataAdapter, error) { + adapter := &DataAdapter{} + + if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" { + pool, err := pgxpool.New(ctx, dbURL) + if err != nil { + return nil, err + } + adapter.pgPool = pool + } + + if redisURL := os.Getenv("REDIS_URL"); redisURL != "" { + opt, _ := redis.ParseURL(redisURL) + adapter.redisClient = redis.NewClient(opt) + } + + if os.Getenv("AWS_ACCESS_KEY_ID") != "" { + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return nil, err + } + adapter.s3Client = s3.NewFromConfig(cfg) + } + + return adapter, nil +} +``` + +## Installation + +```bash +# Initialize Go module +go mod init github.com/lippytm/transparency-logic-time-machine-bots + +# Install dependencies +go get github.com/sashabaranov/go-openai +go get github.com/ethereum/go-ethereum +go get github.com/gagliardetto/solana-go +# ... etc +``` diff --git a/sdk/PYTHON_ADAPTERS.md b/sdk/PYTHON_ADAPTERS.md new file mode 100644 index 0000000..f1004dd --- /dev/null +++ b/sdk/PYTHON_ADAPTERS.md @@ -0,0 +1,120 @@ +# Python Equivalent Adapters + +This document provides guidance for implementing equivalent adapters in Python. + +## AI Adapter (Python) + +```python +# requirements.txt or pyproject.toml +openai>=1.0.0 +transformers>=4.30.0 # optional, heavy install +huggingface-hub>=0.16.0 +langchain>=0.1.0 +llama-index>=0.9.0 +pinecone-client>=2.2.0 # optional +weaviate-client>=3.20.0 # optional +chromadb>=0.4.0 # optional +``` + +**Example usage:** +```python +from openai import OpenAI +from langchain.llms import OpenAI as LangChainOpenAI +import os + +class AIAdapter: + def __init__(self, config=None): + self.openai_client = OpenAI(api_key=os.getenv('OPENAI_API_KEY')) + # Initialize other services as needed + + @classmethod + def from_env(cls): + return cls() +``` + +## Web3 Adapter (Python) + +```python +# requirements.txt +web3>=6.0.0 +solana>=0.30.0 +solders>=0.18.0 +anchorpy>=0.18.0 # optional +``` + +**Example usage:** +```python +from web3 import Web3 +from solana.rpc.api import Client as SolanaClient +import os + +class Web3Adapter: + def __init__(self, config=None): + if os.getenv('ETH_RPC_URL'): + self.w3 = Web3(Web3.HTTPProvider(os.getenv('ETH_RPC_URL'))) + if os.getenv('SOLANA_RPC_URL'): + self.solana = SolanaClient(os.getenv('SOLANA_RPC_URL')) +``` + +## Messaging Adapter (Python) + +```python +# requirements.txt +slack-sdk>=3.20.0 +discord.py>=2.3.0 +``` + +**Example usage:** +```python +from slack_sdk import WebClient +import discord +import os + +class MessagingAdapter: + def __init__(self, config=None): + if os.getenv('SLACK_BOT_TOKEN'): + self.slack = WebClient(token=os.getenv('SLACK_BOT_TOKEN')) + if os.getenv('DISCORD_BOT_TOKEN'): + self.discord_client = discord.Client() +``` + +## Data Adapter (Python) + +```python +# requirements.txt +psycopg2-binary>=2.9.0 # or asyncpg for async +redis>=4.5.0 +boto3>=1.28.0 +ipfshttpclient>=0.8.0 +``` + +**Example usage:** +```python +import psycopg2 +import redis +import boto3 +import ipfshttpclient +import os + +class DataAdapter: + def __init__(self, config=None): + if os.getenv('DATABASE_URL'): + self.pg_conn = psycopg2.connect(os.getenv('DATABASE_URL')) + if os.getenv('REDIS_URL'): + self.redis = redis.from_url(os.getenv('REDIS_URL')) + if os.getenv('AWS_ACCESS_KEY_ID'): + self.s3 = boto3.client('s3') +``` + +## Installation Notes + +For heavy dependencies (transformers, chromadb), use optional extras: + +```toml +# pyproject.toml +[project.optional-dependencies] +ai-heavy = ["transformers>=4.30.0", "chromadb>=0.4.0"] +vector-stores = ["pinecone-client>=2.2.0", "weaviate-client>=3.20.0"] +``` + +Install with: `pip install .[ai-heavy,vector-stores]` diff --git a/sdk/RUST_ADAPTERS.md b/sdk/RUST_ADAPTERS.md new file mode 100644 index 0000000..b703e5e --- /dev/null +++ b/sdk/RUST_ADAPTERS.md @@ -0,0 +1,207 @@ +# Rust Equivalent Adapters + +This document provides guidance for implementing equivalent adapters in Rust. + +## AI Adapter (Rust) + +```toml +# Cargo.toml +[dependencies] +async-openai = "0.17" +reqwest = { version = "0.11", features = ["json"] } +tokio = { version = "1.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +# Heavy/optional dependencies +[dependencies.llm-chain] +version = "0.13" +optional = true + +[features] +ai-heavy = ["llm-chain"] +``` + +**Example usage:** +```rust +use async_openai::{Client, config::OpenAIConfig}; +use std::env; + +pub struct AIAdapter { + openai_client: Option>, +} + +impl AIAdapter { + pub fn from_env() -> Self { + let openai_client = env::var("OPENAI_API_KEY") + .ok() + .map(|key| { + let config = OpenAIConfig::new().with_api_key(key); + Client::with_config(config) + }); + + Self { openai_client } + } +} +``` + +## Web3 Adapter (Rust) + +```toml +# Cargo.toml +[dependencies] +ethers = "2.0" +solana-client = "1.17" +solana-sdk = "1.17" +anchor-client = { version = "0.29", optional = true } + +[features] +solana-anchor = ["anchor-client"] +``` + +**Example usage:** +```rust +use ethers::providers::{Provider, Http}; +use solana_client::rpc_client::RpcClient; +use std::env; + +pub struct Web3Adapter { + eth_provider: Option>, + solana_client: Option, +} + +impl Web3Adapter { + pub fn from_env() -> Result> { + let eth_provider = env::var("ETH_RPC_URL") + .ok() + .and_then(|url| Provider::::try_from(url).ok()); + + let solana_client = env::var("SOLANA_RPC_URL") + .ok() + .map(|url| RpcClient::new(url)); + + Ok(Self { + eth_provider, + solana_client, + }) + } +} +``` + +## Messaging Adapter (Rust) + +```toml +# Cargo.toml +[dependencies] +slack-morphism = "1.0" +serenity = "0.12" +tokio = { version = "1.0", features = ["full"] } +``` + +**Example usage:** +```rust +use slack_morphism::prelude::*; +use serenity::Client as DiscordClient; +use std::env; + +pub struct MessagingAdapter { + slack_client: Option>, + // Discord client initialization is more complex, typically done in main +} + +impl MessagingAdapter { + pub fn from_env() -> Self { + let slack_client = env::var("SLACK_BOT_TOKEN") + .ok() + .map(|_| { + SlackClient::new(SlackClientHyperConnector::new()) + }); + + Self { slack_client } + } +} +``` + +## Data Adapter (Rust) + +```toml +# Cargo.toml +[dependencies] +tokio-postgres = "0.7" +redis = { version = "0.24", features = ["tokio-comp"] } +rusoto_s3 = "0.48" +rusoto_core = "0.48" +ipfs-api-backend-hyper = "0.6" + +[dependencies.sqlx] +version = "0.7" +features = ["postgres", "runtime-tokio-native-tls"] +optional = true + +[features] +sqlx-support = ["sqlx"] +``` + +**Example usage:** +```rust +use tokio_postgres::{Client, NoTls}; +use redis::Client as RedisClient; +use rusoto_s3::S3Client; +use rusoto_core::Region; +use std::env; + +pub struct DataAdapter { + // Note: Connection setup is async and typically done in initialization +} + +impl DataAdapter { + pub async fn from_env() -> Result> { + // PostgreSQL setup + if let Ok(db_url) = env::var("DATABASE_URL") { + let (client, connection) = tokio_postgres::connect(&db_url, NoTls).await?; + // Spawn connection in background + tokio::spawn(async move { + if let Err(e) = connection.await { + eprintln!("connection error: {}", e); + } + }); + } + + // Redis setup + if let Ok(redis_url) = env::var("REDIS_URL") { + let redis_client = RedisClient::open(redis_url)?; + } + + // S3 setup + if env::var("AWS_ACCESS_KEY_ID").is_ok() { + let s3_client = S3Client::new(Region::default()); + } + + Ok(Self {}) + } +} +``` + +## Installation + +```bash +# Create new Rust project +cargo new transparency-logic-time-machine-bots +cd transparency-logic-time-machine-bots + +# Add dependencies +cargo add async-openai ethers solana-client tokio +cargo add --optional llm-chain anchor-client + +# Build with optional features +cargo build --features ai-heavy,solana-anchor +``` + +## Linux Compatibility Notes + +Most Rust crates are Linux-compatible out of the box. For optimal performance: + +- Use `tokio` runtime with `multi-threaded` feature +- For production builds: `cargo build --release` +- Consider using `jemalloc` for better memory allocation +- OpenSSL development packages required: `apt-get install libssl-dev pkg-config` diff --git a/sdk/ai/adapter.ts b/sdk/ai/adapter.ts new file mode 100644 index 0000000..dae606f --- /dev/null +++ b/sdk/ai/adapter.ts @@ -0,0 +1,91 @@ +/** + * AI Adapter - Integration with @lippytm/ai-sdk + * + * This adapter provides a unified interface for AI services including: + * - OpenAI + * - Hugging Face (transformers, inference) + * - LangChain + * - LlamaIndex + * - Vector stores (Pinecone, Weaviate, Chroma) + * + * Environment Variables: + * - OPENAI_API_KEY: OpenAI API key + * - HF_API_TOKEN: Hugging Face API token + * - PINECONE_API_KEY: Pinecone API key (optional) + * - PINECONE_ENVIRONMENT: Pinecone environment (optional) + * - WEAVIATE_URL: Weaviate instance URL (optional) + * - WEAVIATE_API_KEY: Weaviate API key (optional) + * + * Python equivalent: Use @lippytm/ai-sdk Python bindings or openai, transformers, langchain packages + * Go equivalent: Use go-openai, go-langchain libraries + * Rust equivalent: Use async-openai, llm-chain crates + */ + +// Type definitions for external SDK - replace with actual import when @lippytm/ai-sdk is available +export interface AIConfig { + apiKey?: string; + model?: string; +} + +export interface AIAdapterConfig { + openai?: { + apiKey: string; + model?: string; + }; + huggingface?: { + apiToken: string; + model?: string; + }; + langchain?: { + enabled: boolean; + }; + vectorStore?: { + provider: 'pinecone' | 'weaviate' | 'chroma'; + config: Record; + }; +} + +export class AIAdapter { + private config: AIAdapterConfig; + + constructor(config: AIAdapterConfig) { + this.config = config; + } + + /** + * Factory method to create AI adapter from environment variables + * TODO: Add proper secret management integration + */ + static fromEnv(): AIAdapter { + return new AIAdapter({ + openai: process.env.OPENAI_API_KEY ? { + apiKey: process.env.OPENAI_API_KEY, + model: process.env.OPENAI_MODEL || 'gpt-4' + } : undefined, + huggingface: process.env.HF_API_TOKEN ? { + apiToken: process.env.HF_API_TOKEN, + model: process.env.HF_MODEL + } : undefined, + langchain: { + enabled: process.env.LANGCHAIN_ENABLED === 'true' + }, + vectorStore: process.env.VECTOR_STORE_PROVIDER ? { + provider: process.env.VECTOR_STORE_PROVIDER as any, + config: { + apiKey: process.env.VECTOR_STORE_API_KEY, + environment: process.env.VECTOR_STORE_ENVIRONMENT, + url: process.env.VECTOR_STORE_URL + } + } : undefined + }); + } + + getConfig(): AIAdapterConfig { + return this.config; + } + + // TODO: Implement actual AI SDK integration methods + // TODO: Add vector store initialization + // TODO: Add LangChain chain builders + // TODO: Add LlamaIndex query engine +} diff --git a/sdk/data/adapter.ts b/sdk/data/adapter.ts new file mode 100644 index 0000000..c75f773 --- /dev/null +++ b/sdk/data/adapter.ts @@ -0,0 +1,100 @@ +/** + * Data Adapter - Multi-source data integration + * + * Supports: + * - PostgreSQL via pg + * - Redis + * - AWS S3 + * - IPFS + * + * Environment Variables: + * - DATABASE_URL: PostgreSQL connection string + * - REDIS_URL: Redis connection string + * - AWS_ACCESS_KEY_ID: AWS access key + * - AWS_SECRET_ACCESS_KEY: AWS secret key + * - AWS_REGION: AWS region + * - S3_BUCKET: S3 bucket name + * - IPFS_URL: IPFS node URL + * + * Python equivalent: Use psycopg2/asyncpg, redis-py, boto3, ipfshttpclient packages + * Go equivalent: Use pgx, go-redis, aws-sdk-go, go-ipfs-api libraries + * Rust equivalent: Use sqlx/tokio-postgres, redis-rs, rusoto_s3, ipfs-api crates + */ + +export interface DataAdapterConfig { + postgres?: { + connectionString: string; + poolConfig?: any; + }; + redis?: { + url: string; + }; + s3?: { + accessKeyId: string; + secretAccessKey: string; + region: string; + bucket?: string; + }; + ipfs?: { + url: string; + }; +} + +export class DataAdapter { + private config: DataAdapterConfig; + private pgPool?: any; // Pool + private redisClient?: any; // RedisClientType + private s3Client?: any; // S3Client + private ipfsClient?: any; + + constructor(config: DataAdapterConfig) { + this.config = config; + // Note: Actual initialization requires pg, redis, @aws-sdk/client-s3, ipfs-http-client to be installed + // Initialize when dependencies are available + } + + /** + * Factory method to create Data adapter from environment variables + * TODO: Add proper secret management integration + */ + static fromEnv(): DataAdapter { + return new DataAdapter({ + postgres: process.env.DATABASE_URL ? { + connectionString: process.env.DATABASE_URL + } : undefined, + redis: process.env.REDIS_URL ? { + url: process.env.REDIS_URL + } : undefined, + s3: (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) ? { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + region: process.env.AWS_REGION || 'us-east-1', + bucket: process.env.S3_BUCKET + } : undefined, + ipfs: process.env.IPFS_URL ? { + url: process.env.IPFS_URL + } : undefined + }); + } + + getConfig(): DataAdapterConfig { + return this.config; + } + + // TODO: Initialize PostgreSQL pool when dependency is available + // Example: this.pgPool = new Pool({ connectionString: this.config.postgres.connectionString }); + + // TODO: Initialize Redis client when dependency is available + // Example: this.redisClient = createClient({ url: this.config.redis.url }); + + // TODO: Initialize S3 client when dependency is available + // Example: this.s3Client = new S3Client({ credentials: {...}, region: this.config.s3.region }); + + // TODO: Initialize IPFS client when dependency is available + // Example: this.ipfsClient = create({ url: this.config.ipfs.url }); + + // TODO: Add query helpers + // TODO: Add caching utilities + // TODO: Add S3 upload/download helpers + // TODO: Add IPFS pin/unpin helpers +} diff --git a/sdk/index.ts b/sdk/index.ts new file mode 100644 index 0000000..99e8ea0 --- /dev/null +++ b/sdk/index.ts @@ -0,0 +1,34 @@ +/** + * Main SDK index - exports all adapters + */ + +import { AIAdapter, AIAdapterConfig } from './ai/adapter'; +import { Web3Adapter, Web3AdapterConfig } from './web3/adapter'; +import { MessagingAdapter, MessagingAdapterConfig } from './messaging/adapter'; +import { DataAdapter, DataAdapterConfig } from './data/adapter'; + +export { AIAdapter, AIAdapterConfig }; +export { Web3Adapter, Web3AdapterConfig }; +export { MessagingAdapter, MessagingAdapterConfig }; +export { DataAdapter, DataAdapterConfig }; + +export interface SDKConfig { + ai?: any; + web3?: any; + messaging?: any; + data?: any; +} + +/** + * Factory class to create all adapters from environment variables + */ +export class SDK { + static createFromEnv() { + return { + ai: AIAdapter.fromEnv(), + web3: Web3Adapter.fromEnv(), + messaging: MessagingAdapter.fromEnv(), + data: DataAdapter.fromEnv() + }; + } +} diff --git a/sdk/messaging/adapter.ts b/sdk/messaging/adapter.ts new file mode 100644 index 0000000..bb586fb --- /dev/null +++ b/sdk/messaging/adapter.ts @@ -0,0 +1,72 @@ +/** + * Messaging Adapter - Multi-platform messaging integration + * + * Supports: + * - Slack via @slack/web-api + * - Discord via discord.js + * + * Environment Variables: + * - SLACK_BOT_TOKEN: Slack bot token + * - SLACK_SIGNING_SECRET: Slack signing secret + * - DISCORD_BOT_TOKEN: Discord bot token + * + * Python equivalent: Use slack-sdk, discord.py packages + * Go equivalent: Use slack-go, discordgo libraries + * Rust equivalent: Use slack-rust, serenity crates + */ + +export interface MessagingAdapterConfig { + slack?: { + botToken: string; + signingSecret?: string; + }; + discord?: { + botToken: string; + intents?: number[]; + }; +} + +export class MessagingAdapter { + private config: MessagingAdapterConfig; + private slackClient?: any; // WebClient + private discordClient?: any; // Client + + constructor(config: MessagingAdapterConfig) { + this.config = config; + // Note: Actual initialization requires @slack/web-api and discord.js to be installed + // Initialize when dependencies are available + } + + /** + * Factory method to create Messaging adapter from environment variables + * TODO: Add proper secret management integration + */ + static fromEnv(): MessagingAdapter { + return new MessagingAdapter({ + slack: process.env.SLACK_BOT_TOKEN ? { + botToken: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET + } : undefined, + discord: process.env.DISCORD_BOT_TOKEN ? { + botToken: process.env.DISCORD_BOT_TOKEN, + // GatewayIntentBits values would be used here when discord.js is available + intents: [] + } : undefined + }); + } + + getConfig(): MessagingAdapterConfig { + return this.config; + } + + // TODO: Initialize Slack client when dependency is available + // Example: this.slackClient = new WebClient(this.config.slack.botToken); + + // TODO: Initialize Discord client when dependency is available + // Example: this.discordClient = new Client({ intents: this.config.discord.intents }); + + // TODO: Add message sending helpers + // TODO: Add event handlers + // TODO: Add slash command support + // TODO: Add interactive component handlers +} diff --git a/sdk/web3/adapter.ts b/sdk/web3/adapter.ts new file mode 100644 index 0000000..2e721b6 --- /dev/null +++ b/sdk/web3/adapter.ts @@ -0,0 +1,84 @@ +/** + * Web3 Adapter - Multi-chain blockchain integration + * + * Supports: + * - EVM chains (Ethereum, Polygon, BSC, etc.) via ethers.js + * - Solana via @solana/web3.js and Anchor + * - Extension points for other chains + * + * Environment Variables: + * - ETH_RPC_URL: Ethereum RPC endpoint + * - ETH_PRIVATE_KEY: Ethereum private key (use secret manager in production) + * - SOLANA_RPC_URL: Solana RPC endpoint + * - SOLANA_PRIVATE_KEY: Solana private key (use secret manager in production) + * + * Python equivalent: Use web3.py for EVM, solana-py for Solana + * Go equivalent: Use go-ethereum, solana-go libraries + * Rust equivalent: Use ethers-rs, solana-sdk crates + */ + +export interface Web3AdapterConfig { + evm?: { + rpcUrl: string; + privateKey?: string; + chainId?: number; + }; + solana?: { + rpcUrl: string; + privateKey?: string; + commitment?: 'processed' | 'confirmed' | 'finalized'; + }; + // Extension points for other chains + other?: { + chain: string; + config: Record; + }[]; +} + +export class Web3Adapter { + private config: Web3AdapterConfig; + private evmProvider?: any; // ethers.JsonRpcProvider + private evmWallet?: any; // ethers.Wallet + private solanaConnection?: any; // Connection + private solanaKeypair?: any; // Keypair + + constructor(config: Web3AdapterConfig) { + this.config = config; + // Note: Actual initialization requires ethers and @solana/web3.js to be installed + // Initialize when dependencies are available + } + + /** + * Factory method to create Web3 adapter from environment variables + * TODO: Add proper secret management integration + */ + static fromEnv(): Web3Adapter { + return new Web3Adapter({ + evm: process.env.ETH_RPC_URL ? { + rpcUrl: process.env.ETH_RPC_URL, + privateKey: process.env.ETH_PRIVATE_KEY, + chainId: process.env.ETH_CHAIN_ID ? parseInt(process.env.ETH_CHAIN_ID) : undefined + } : undefined, + solana: process.env.SOLANA_RPC_URL ? { + rpcUrl: process.env.SOLANA_RPC_URL, + privateKey: process.env.SOLANA_PRIVATE_KEY, + commitment: (process.env.SOLANA_COMMITMENT as any) || 'confirmed' + } : undefined + }); + } + + getConfig(): Web3AdapterConfig { + return this.config; + } + + // TODO: Initialize EVM provider with ethers.js when dependency is available + // Example: this.evmProvider = new ethers.JsonRpcProvider(this.config.evm.rpcUrl); + + // TODO: Initialize Solana connection when dependency is available + // Example: this.solanaConnection = new Connection(this.config.solana.rpcUrl); + + // TODO: Add contract interaction methods + // TODO: Add transaction signing and sending + // TODO: Add Anchor program interaction helpers + // TODO: Add chain-specific utilities +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..8965217 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,5 @@ +/** + * Main entry point for the SDK + */ + +export * from '../sdk'; diff --git a/test/config.test.js b/test/config.test.js new file mode 100644 index 0000000..b1fe4d3 --- /dev/null +++ b/test/config.test.js @@ -0,0 +1,28 @@ +/** + * Smoke test for config loader + * Run with: node --test test/config.test.js + */ + +const { test } = require('node:test'); +const { strict: assert } = require('node:assert'); + +test('Environment variable loading - smoke test', () => { + // Simple test that environment can be read + process.env.TEST_VAR = 'test_value'; + assert.equal(process.env.TEST_VAR, 'test_value', 'Should read environment variable'); +}); + +test('Config factory pattern - smoke test', () => { + // Test simple factory pattern + class ConfigLoader { + static fromEnv() { + return { + openai: process.env.OPENAI_API_KEY ? { apiKey: process.env.OPENAI_API_KEY } : undefined + }; + } + } + + const config = ConfigLoader.fromEnv(); + assert.ok(config !== null, 'Config should not be null'); + assert.ok(typeof config === 'object', 'Config should be an object'); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ddf041 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "declaration": true, + "outDir": "./dist", + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "types": ["node"] + }, + "include": ["src/**/*", "sdk/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.js", "test"] +}