Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): refactor how inference providers are added and configured #475

Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
a11b8ef
add jsf for json schema
AgustinRamiroDiaz Sep 3, 2024
db9b895
configure pytest vscode
AgustinRamiroDiaz Sep 3, 2024
fd379bc
configure dockerignore
AgustinRamiroDiaz Sep 3, 2024
fd8fc06
improve schema
AgustinRamiroDiaz Sep 3, 2024
cef6c64
test hypothesis_jsonschema
AgustinRamiroDiaz Sep 3, 2024
1575c13
test other libraries
AgustinRamiroDiaz Sep 4, 2024
66e3f4e
add default providers
AgustinRamiroDiaz Sep 4, 2024
bec7836
move tests
AgustinRamiroDiaz Sep 4, 2024
def5e9e
refactor
AgustinRamiroDiaz Sep 4, 2024
ed43cc8
improve schema
AgustinRamiroDiaz Sep 4, 2024
2e9a0d1
fix default
AgustinRamiroDiaz Sep 4, 2024
9e23c13
fix schema
AgustinRamiroDiaz Sep 4, 2024
d3dd244
extend schema
AgustinRamiroDiaz Sep 4, 2024
7b7d63b
extend schema
AgustinRamiroDiaz Sep 4, 2024
fd36122
add llm provider object
AgustinRamiroDiaz Sep 4, 2024
ed85d6d
add more endpoints for configuring providers
AgustinRamiroDiaz Sep 4, 2024
fd5c6d3
test
AgustinRamiroDiaz Sep 5, 2024
6cab720
add random creation
AgustinRamiroDiaz Sep 5, 2024
53e919e
use hypothesis for random generation
AgustinRamiroDiaz Sep 5, 2024
a19599f
fix pytest precommit
AgustinRamiroDiaz Sep 5, 2024
3824a7d
fix requirements
AgustinRamiroDiaz Sep 5, 2024
69168ed
remove gpt 3.5
AgustinRamiroDiaz Sep 5, 2024
edd48ce
improve backend cmd
AgustinRamiroDiaz Sep 6, 2024
2ee9a2c
remove defaults.json
AgustinRamiroDiaz Sep 6, 2024
a370f20
refactor get random validator config
AgustinRamiroDiaz Sep 6, 2024
90f47e9
add tests
AgustinRamiroDiaz Sep 6, 2024
e1b561a
add more tests
AgustinRamiroDiaz Sep 6, 2024
8cb8b0f
add tests
AgustinRamiroDiaz Sep 6, 2024
da5f115
refactor to use random_validator_config
AgustinRamiroDiaz Sep 6, 2024
26c1ca1
configure endpoints
AgustinRamiroDiaz Sep 6, 2024
bdccdf8
update e2e tests
AgustinRamiroDiaz Sep 6, 2024
e20311d
add validators tests
AgustinRamiroDiaz Sep 6, 2024
6339de2
add llm provider endpoint test
AgustinRamiroDiaz Sep 6, 2024
0c0f457
fix todo
AgustinRamiroDiaz Sep 6, 2024
4ea3145
remove venv in pre-commit
AgustinRamiroDiaz Sep 6, 2024
5fd2727
improve types
AgustinRamiroDiaz Sep 9, 2024
73ce604
remove unnecessary import
AgustinRamiroDiaz Sep 9, 2024
a8c2cfd
add plugins
AgustinRamiroDiaz Sep 9, 2024
3aa84d9
improve plugins
AgustinRamiroDiaz Sep 9, 2024
7e41f48
docs
AgustinRamiroDiaz Sep 10, 2024
7c0c898
add plugin config + fix docker config + minor extras
AgustinRamiroDiaz Sep 10, 2024
2b03f13
fix dockerfile
AgustinRamiroDiaz Sep 10, 2024
f76ef90
hotfix cyclic error
AgustinRamiroDiaz Sep 10, 2024
f6d9a08
start adding plugin configuration to validator, node and genvm
AgustinRamiroDiaz Sep 10, 2024
fe391ad
improve migration
AgustinRamiroDiaz Sep 10, 2024
73b4de4
fix migration
AgustinRamiroDiaz Sep 11, 2024
5746c2a
fix tests
AgustinRamiroDiaz Sep 11, 2024
c9b7a6e
ci: add db integration tests
AgustinRamiroDiaz Sep 11, 2024
c5209ac
fix unit test
AgustinRamiroDiaz Sep 11, 2024
53c3361
fix tests
AgustinRamiroDiaz Sep 11, 2024
96f1983
fix tests
AgustinRamiroDiaz Sep 11, 2024
924ba5e
fix node
AgustinRamiroDiaz Sep 11, 2024
c9d757b
fixt tests
AgustinRamiroDiaz Sep 11, 2024
1104d5f
fix test
AgustinRamiroDiaz Sep 11, 2024
cf55869
fix tests
AgustinRamiroDiaz Sep 11, 2024
f04b1b2
fix tests
AgustinRamiroDiaz Sep 11, 2024
610c081
improve plugins
AgustinRamiroDiaz Sep 11, 2024
723d126
fix tests
AgustinRamiroDiaz Sep 11, 2024
801f45a
fix tests
AgustinRamiroDiaz Sep 12, 2024
a2c74d2
fix tests
AgustinRamiroDiaz Sep 12, 2024
f778e7c
fix tests
AgustinRamiroDiaz Sep 12, 2024
7ba4058
test
AgustinRamiroDiaz Sep 12, 2024
329ec43
test
AgustinRamiroDiaz Sep 12, 2024
59f8f88
fix tests
AgustinRamiroDiaz Sep 12, 2024
0461bf1
improve schema
AgustinRamiroDiaz Sep 12, 2024
95f2ec9
unify HeuristAI and OpenAI plugins
AgustinRamiroDiaz Sep 12, 2024
59e2885
fix tests
AgustinRamiroDiaz Sep 12, 2024
74d8acf
start adding anthropic plugin
AgustinRamiroDiaz Sep 12, 2024
749d8ea
fix: register anthropic
AgustinRamiroDiaz Sep 13, 2024
048886e
fix validators in the frontend
AgustinRamiroDiaz Sep 13, 2024
25b39c9
fix endpoint
AgustinRamiroDiaz Sep 13, 2024
770adc6
add new openai models
AgustinRamiroDiaz Sep 13, 2024
8d2600f
fix anthropic plugin
AgustinRamiroDiaz Sep 13, 2024
6f85c65
use protocolt instead of ABC for Plugin interface
AgustinRamiroDiaz Sep 15, 2024
a16920c
feat: load default providers in a thread and cache
AgustinRamiroDiaz Sep 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ frontend/src/assets/examples
frontend/.nyc_output
frontend/coverage
frontend/vite.config.ts.timestamp-*

# Python
# Byte-compiled / optimized / DLL files
**/__pycache__/
**/*.py[cod]
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ HEURISTAIMODELSURL = 'https://raw.githubusercontent.com/heurist-network/heurist
# If you want to use Heurist AI add your key here
HEURISTAIAPIKEY = '<add_your_heuristai_api_key_here>'

# If you want to use Anthropic (Claude AI) add your key here and uncomment the line
# ANTHROPIC_API_KEY = '<add_your_anthropic_api_key_here>'

# Front end container details
VITE_JSON_RPC_SERVER_URL = 'http://127.0.0.1:4000/api'
VITE_WS_SERVER_URL = 'ws://127.0.0.1:4000'
Expand Down
28 changes: 27 additions & 1 deletion .github/workflows/backend_integration_tests_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jobs:
- name: Copy .env file
run: cp .env.example .env

# TODO: we should also add also heuristai and anthropic keys to the e2e tests and test all providers

- name: Set OPENAIKEY in the .env file so it can be loaded from the environment
env:
OPENAIKEY: ${{ secrets.OPENAIKEY }}
Expand All @@ -58,7 +60,7 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-

- name: Build Docker image
- name: Build Docker images
run: docker compose build

- name: Run Docker Compose
Expand Down Expand Up @@ -106,3 +108,27 @@ jobs:
- name: Shutdown Docker Compose
if: always()
run: docker compose down

db-integration-test:
needs: triggers
if: ${{ needs.triggers.outputs.is_pull_request_opened == 'true' || needs.triggers.outputs.is_pull_request_review_approved == 'true' || needs.triggers.outputs.is_pull_request_labeled_with_run_tests == 'true' }}

runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

- name: Run Docker Compose
run: docker compose -f tests/db-sqlalchemy/docker-compose.yml --project-directory . up tests --build --force-recreate --always-recreate-deps
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repos:
hooks:
- id: backend-unit-pytest
name: backend unit tests with pytest
entry: python3 -m pytest backend
entry: pytest tests/unit
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra: moved unit tests

language: system
types: [python]
pass_filenames: false
Expand Down
8 changes: 6 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"python.testing.pytestArgs": ["tests"],
"python.testing.pytestArgs": ["tests", "backend"],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
"python.testing.pytestEnabled": true,
"sonarlint.connectedMode.project": {
"connectionId": "YeagerAI",
"projectKey": "yeagerai_genlayer-simulator"
}
}
Comment on lines +5 to 12
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra: pytest and sonar vscode config

35 changes: 24 additions & 11 deletions backend/consensus/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
)
from backend.database_handler.accounts_manager import AccountsManager
from backend.database_handler.types import ConsensusData
from backend.domain.types import LLMProvider, Validator
from backend.node.base import Node
from backend.node.genvm.types import ExecutionMode, Vote
from backend.protocol_rpc.message_handler.base import MessageHandler
Expand Down Expand Up @@ -128,12 +129,18 @@ async def exec_transaction(
# Create Leader
leader_node = Node(
contract_snapshot=contract_snapshot,
address=leader["address"],
validator_mode=ExecutionMode.LEADER,
stake=leader["stake"],
provider=leader["provider"],
model=leader["model"],
config=leader["config"],
validator=Validator(
address=leader["address"],
stake=leader["stake"],
llmprovider=LLMProvider(
provider=leader["provider"],
model=leader["model"],
config=leader["config"],
plugin=leader["plugin"],
plugin_config=leader["plugin_config"],
),
),
msg_handler=self.msg_handler,
)

Expand All @@ -149,16 +156,22 @@ async def exec_transaction(
validator_nodes = [
Node(
contract_snapshot=contract_snapshot,
address=validator["address"],
validator_mode=ExecutionMode.VALIDATOR,
stake=validator["stake"],
provider=validator["provider"],
model=validator["model"],
config=validator["config"],
validator=Validator(
address=validator["address"],
stake=validator["stake"],
llmprovider=LLMProvider(
provider=validator["provider"],
model=validator["model"],
config=validator["config"],
plugin=validator["plugin"],
plugin_config=validator["plugin_config"],
),
),
leader_receipt=leader_receipt,
msg_handler=self.msg_handler,
)
for i, validator in enumerate(remaining_validators)
for validator in remaining_validators
]

# Validators execute transaction
Expand Down
4 changes: 3 additions & 1 deletion backend/consensus/vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ def select_random_validators(all_validators: list, num_validators: int) -> list:
return [all_validators[i] for i in unique_indices]


def get_validators_for_transaction(all_validators: list, num_validators: int) -> tuple:
def get_validators_for_transaction(
all_validators: list, num_validators: int
) -> tuple[dict, list]:
selected_validators = select_random_validators(all_validators, num_validators)
leader = selected_validators[0]
remaining_validators = selected_validators[1 : num_validators + 1]
Expand Down
2 changes: 1 addition & 1 deletion backend/database_handler/alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ script_location = migration

# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
prepend_sys_path = ./backend/database_handler
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed for imports


# timezone to use when rendering the date within the migration file
# as well as the filename.
Expand Down
78 changes: 78 additions & 0 deletions backend/database_handler/llm_providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from backend.domain.types import LLMProvider
from backend.node.create_nodes.providers import get_default_providers
from .models import LLMProviderDBModel
from sqlalchemy.orm import Session


class LLMProviderRegistry:
def __init__(self, session: Session):
self.session = session

def reset_defaults(self):
"""Reset all providers to their default values."""
self.session.query(LLMProviderDBModel).delete()

providers = get_default_providers()
for provider in providers:
self.session.add(_to_db_model(provider))

self.session.commit()

def get_all(self) -> list[LLMProvider]:
return [
_to_domain(provider)
for provider in self.session.query(LLMProviderDBModel).all()
]

def get_all_dict(self) -> list[dict]:
return [
_to_domain(provider).__dict__
for provider in self.session.query(LLMProviderDBModel).all()
]

def add(self, provider: LLMProvider) -> int:
model = _to_db_model(provider)
self.session.add(model)
self.session.commit()
return model.id

def update(self, id: int, provider: LLMProvider):
self.session.query(LLMProviderDBModel).filter(
LLMProviderDBModel.id == id
).update(
{
LLMProviderDBModel.provider: provider.provider,
LLMProviderDBModel.model: provider.model,
LLMProviderDBModel.config: provider.config,
LLMProviderDBModel.plugin: provider.plugin,
LLMProviderDBModel.plugin_config: provider.plugin_config,
}
)
self.session.commit()

def delete(self, id: int):
self.session.query(LLMProviderDBModel).filter(
LLMProviderDBModel.id == id
).delete()
self.session.commit()


def _to_domain(db_model: LLMProvider) -> LLMProvider:
return LLMProvider(
id=db_model.id,
provider=db_model.provider,
model=db_model.model,
config=db_model.config,
plugin=db_model.plugin,
plugin_config=db_model.plugin_config,
)


def _to_db_model(domain: LLMProvider) -> LLMProviderDBModel:
return LLMProviderDBModel(
provider=domain.provider,
model=domain.model,
config=domain.config,
plugin=domain.plugin,
plugin_config=domain.plugin_config,
)
5 changes: 4 additions & 1 deletion backend/database_handler/migration/env.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from logging.config import fileConfig
import sys

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context
import os

# set up Python path as the project root directory, so that we can import as backend...
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..")))

DB_URL = os.environ.get("DB_URL")

Expand All @@ -21,7 +24,7 @@

# add your model's MetaData object here
# for 'autogenerate' support
from models import Base
from backend.database_handler.models import Base

target_metadata = Base.metadata

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""add plugin and plugin_config to validators

Revision ID: 986d9a6b0dda
Revises: db38e78684a8
Create Date: 2024-09-10 14:47:10.730407

"""

from typing import Sequence, Union

from alembic import op
from sqlalchemy import column, table
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

from backend.node.create_nodes.providers import get_default_provider_for

# revision identifiers, used by Alembic.
revision: str = "986d9a6b0dda"
down_revision: Union[str, None] = "db38e78684a8"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.add_column("validators", sa.Column("plugin", sa.String(length=255)))
op.add_column(
"validators",
sa.Column("plugin_config", postgresql.JSONB(astext_type=sa.Text())),
)

# Modify below

# Create a table object for the validators table
validators = table(
"validators",
column("id", sa.Integer),
column("provider", sa.String),
column("model", sa.String),
column("plugin", sa.String),
column("plugin_config", postgresql.JSONB),
column("config", postgresql.JSONB),
)

# Fetch existing data
conn = op.get_bind()
results = conn.execute(validators.select())

# Process data and perform updates
for validator in results:
id = validator.id
provider = validator.provider
model = validator.model
default_provider = get_default_provider_for(provider=provider, model=model)
conn.execute(
validators.update()
.where(validators.c.id == id)
.values(
plugin=default_provider.plugin,
plugin_config=default_provider.plugin_config,
config=default_provider.config,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we are overriding existing configs. This is because the schema has changed and it's the simplest way. Handling the logic of migrating current configs is possible, but would be a lot of work and it's probably not a requirement

)
)
# Modify above

op.alter_column(
"validators", "plugin", existing_type=sa.VARCHAR(length=255), nullable=False
)
op.alter_column(
"validators",
"plugin_config",
existing_type=postgresql.JSONB(astext_type=sa.Text()),
nullable=False,
)
op.alter_column(
"validators", "provider", existing_type=sa.VARCHAR(length=255), nullable=False
)
op.alter_column(
"validators", "model", existing_type=sa.VARCHAR(length=255), nullable=False
)


def downgrade() -> None:
op.alter_column(
"validators", "model", existing_type=sa.VARCHAR(length=255), nullable=True
)
op.alter_column(
"validators", "provider", existing_type=sa.VARCHAR(length=255), nullable=True
)
op.drop_column("validators", "plugin_config")
op.drop_column("validators", "plugin")
Loading
Loading