Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5fbd461
chore: updated b64 converse errors and naming for clarity. added make…
MiNeves00 May 2, 2025
75b1590
feat: refactored tracker db folder structure. added alembic migration…
MiNeves00 May 8, 2025
426784e
[fix] bump prerelease version in pyproject.toml
actions-user May 8, 2025
f37bcba
[fix] bump prerelease version in pyproject.toml
actions-user May 8, 2025
e3ab87a
Fix/alembic ignore bigquery (#220)
MiNeves00 May 14, 2025
8d63cb6
[fix] bump prerelease version in pyproject.toml
actions-user May 14, 2025
7cc382d
feat: added o4-mini support (#221)
MiNeves00 May 28, 2025
16cb442
[fix] bump prerelease version in pyproject.toml
actions-user May 28, 2025
b00a87a
feat: tiktoken upgrade
brunoalho99 Nov 17, 2025
3e1d8e5
feat:version update
brunoalho99 Nov 17, 2025
9362e67
feat: version bump
brunoalho99 Nov 17, 2025
90d0ad0
feat: poetry version
brunoalho99 Nov 17, 2025
66d600a
[fix] bump prerelease version in pyproject.toml
actions-user Nov 17, 2025
d3ed532
[fix] bump prerelease version in pyproject.toml
actions-user Nov 17, 2025
beffe43
[fix] bump prerelease version in pyproject.toml
actions-user Nov 18, 2025
e3a0d11
feat: update version
brunoalho99 Nov 18, 2025
269618c
[fix] bump prerelease version in pyproject.toml
actions-user Nov 18, 2025
319727d
feat: remove tiktoken
brunoalho99 Nov 18, 2025
7dcccea
feat: alpha version
brunoalho99 Nov 18, 2025
bbb01fb
Merge branch 'develop' into feature/upgrade_tiktoken
brunoalho99 Nov 18, 2025
7161983
feat: tiktoken upgrade (#223)
brunoalho99 Nov 18, 2025
f28d6ca
[fix] bump prerelease version in pyproject.toml
actions-user Nov 18, 2025
891ca8f
feat: python bump
brunoalho99 Nov 18, 2025
58d587c
[fix] bump prerelease version in pyproject.toml
actions-user Nov 18, 2025
0273e05
[fix] bump prerelease version in pyproject.toml
actions-user Nov 18, 2025
ee45eb8
[fix] bump prerelease version in pyproject.toml
actions-user Jan 15, 2026
80347a1
feat: prompt manager tracker
brunoalho99 Jan 16, 2026
37d8aac
[fix] bump prerelease version in pyproject.toml
actions-user Jan 16, 2026
e2382bc
chore: bump versions
diogoncalves Feb 3, 2026
2cae677
Chore/bump dependencies (#224)
brunoalho99 Feb 4, 2026
ce1044b
[fix] bump prerelease version in pyproject.toml
actions-user Feb 4, 2026
1fbe91a
[fix] bump prerelease version in pyproject.toml
actions-user Feb 4, 2026
71abd4a
[fix] bump prerelease version in pyproject.toml
actions-user Feb 4, 2026
4d48655
feat: bump versions
brunoalho99 Feb 5, 2026
b56e4d7
[fix] bump prerelease version in pyproject.toml
actions-user Feb 5, 2026
1fccd9b
Revise model configurations in config.yaml
diogoncalves Apr 29, 2026
7d63cbc
Fix model names and add new configurations
diogoncalves Apr 29, 2026
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
25 changes: 25 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
OPENAI_API_KEY="sk-proj-XXXXX"
ANTHROPIC_API_KEY="sk-XXXXX"
COHERE_API_KEY="XXXX"
GOOGLE_API_KEY="XXXX"
DECART_API_KEY="XXXX"
AI71_API_KEY="XXXX"
AI21_API_KEY="XXXX"
BEDROCK_ACCESS_KEY="XXXX"
BEDROCK_SECRET_KEY="r+"XXXX""
BEDROCK_REGION="us-west-2"
HUGGING_FACE_API_KEY="hf_"XXXX""
AZURE_API_KEY=""XXXX""
AZURE_API_ENDPOINT="https://XXXXX.openai.azure.com/"
AZURE_API_VERSION="2023-07-01-preview"
ENGINE_HOST="localhost"
ENGINE_PORT=8000
UI_HOST="localhost"
UI_PORT=3000
LOG_LEVEL="info"

#LLMSTUDIO_TRACKING_URI="postgresql://postgres:postgres@localhost:5433/tracker_db"
LLMSTUDIO_TRACKING_URI="sqlite:///./llmstudio_mgmt.db"
LLMSTUDIO_TRACKING_HOST="127.0.0.1"
LLMSTUDIO_TRACKING_PORT="50002"
LLMSTUDIO_ALEMBIC_TABLE_NAME="llmstudio_alembic_version"
17 changes: 15 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,32 @@ jobs:
uses: actions/cache@v3
with:
path: ~/.cache/pypoetry
key: poetry-integration-${{ runner.os }}-${{ hashFiles('libs/llmstudio/poetry.lock') }}
key: poetry-integration-${{ runner.os }}-${{ hashFiles('libs/llmstudio/poetry.lock', 'libs/llmstudio/pyproject.toml') }}
restore-keys: |
poetry-integration-${{ runner.os }}-

# Install llmstudio
- name: Install llmstudio
working-directory: ./libs/llmstudio
run: |
poetry install
poetry install --extras tracker
INTEGRATION_ENV=$(poetry env info --path)
echo $INTEGRATION_ENV
echo "INTEGRATION_ENV=$INTEGRATION_ENV" >> $GITHUB_ENV

# Set Env vars for sqlite db
- name: Set hardcoded DB URI, HOST and PORT
run: |
echo "LLMSTUDIO_TRACKING_URI=sqlite:///./test_tracker.db" >> $GITHUB_ENV
echo "LLMSTUDIO_TRACKING_HOST=127.0.0.1" >> $GITHUB_ENV
echo "LLMSTUDIO_TRACKING_PORT=50002" >> $GITHUB_ENV

# Run Alembic migrations
- name: Run Alembic migrations
run: |
source ${{ env.INTEGRATION_ENV }}/bin/activate
poetry run alembic upgrade head

# Run Integration Tests
- name: Run Integration Tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@ bun.lockb
llmstudio/llm_engine/logs/execution_logs.jsonl
*.db
.prettierignore
db

2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ repos:
hooks:
- id: autoflake
files: libs/
exclude: 'libs/core/llmstudio_core/providers/__init__.py|libs/llmstudio/llmstudio/providers/__init__.py'
exclude: 'libs/core/llmstudio_core/providers/__init__.py|libs/llmstudio/llmstudio/providers/__init__.py|libs/tracker/llmstudio_tracker/db/migrations/env.py|libs/tracker/llmstudio_tracker/base.py'
args:
- --remove-all-unused-imports
- --recursive
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ format:

unit-tests:
pytest libs/core/tests/unit_tests

integration-tests:
pytest libs/llmstudio/tests/integration_tests
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

new line

118 changes: 118 additions & 0 deletions alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
# Use forward slashes (/) also on windows to provide an os agnostic path
script_location = libs/tracker/llmstudio_tracker/db/migrations

# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
# for all available tokens
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s

# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .

# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =

# max length of characters to apply to the "slug" field
# truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; This defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator" below.
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions

# version path separator; As mentioned above, this is the character used to split
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
# Valid values for version_path_separator are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
# version_path_separator = newline
#
# Use os.pathsep. Default configuration used for new projects.
version_path_separator = os

# set to 'true' to search source files recursively
# in each "version_locations" directory
# new in Alembic version 1.10
# recursive_version_locations = false

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8

sqlalchemy.url = placeholder

[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples

# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME

# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
# hooks = ruff
# ruff.type = exec
# ruff.executable = %(here)s/.venv/bin/ruff
# ruff.options = check --fix REVISION_SCRIPT_FILENAME

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARNING
handlers = console
qualname =

[logger_sqlalchemy]
level = WARNING
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
27 changes: 23 additions & 4 deletions examples/core.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@

from llmstudio_core.providers import LLMCore

from llmstudio.providers import LLM
from llmstudio_tracker.tracker import TrackingConfig
from llmstudio.server import start_servers

from pprint import pprint
import os
import asyncio
from dotenv import load_dotenv
import uuid
load_dotenv()

start_servers(proxy=False, tracker=True)

tracking_config = TrackingConfig(
host=os.environ["LLMSTUDIO_TRACKING_HOST"],
port=os.environ["LLMSTUDIO_TRACKING_PORT"]
)

session_id = str(uuid.uuid4())

use_logging = True


def run_provider(provider, model, api_key=None, **kwargs):
print(f"\n\n###RUNNING for <{provider}>, <{model}> ###")
llm = LLMCore(provider=provider, api_key=api_key, **kwargs)

if use_logging:
llm = LLM(provider=provider, api_key=api_key, session_id=session_id, tracking_config=tracking_config, **kwargs)
else:
llm = LLMCore(provider=provider, api_key=api_key, **kwargs)

latencies = {}
print("\nAsync Non-Stream")
Expand Down Expand Up @@ -94,7 +113,7 @@ async def async_stream():
return latencies

def build_chat_request(model: str, chat_input: str, is_stream: bool, max_tokens: int=1000):
if model.startswith(('o1', 'o3')):
if model.startswith(('o1', 'o3', 'o4')):
chat_request = {
"chat_input": chat_input,
"model": model,
Expand Down Expand Up @@ -137,7 +156,7 @@ def multiple_provider_runs(provider:str, model:str, num_runs:int, api_key:str, *
def run_chat_all_providers():
# OpenAI
multiple_provider_runs(provider="openai", model="gpt-4o-mini", api_key=os.environ["OPENAI_API_KEY"], num_runs=1)
multiple_provider_runs(provider="openai", model="o3-mini", api_key=os.environ["OPENAI_API_KEY"], num_runs=1)
multiple_provider_runs(provider="openai", model="o4-mini", api_key=os.environ["OPENAI_API_KEY"], num_runs=1)
#multiple_provider_runs(provider="openai", model="o1-preview", api_key=os.environ["OPENAI_API_KEY"], num_runs=1)


Expand Down
40 changes: 40 additions & 0 deletions libs/core/llmstudio_core/config.yaml
Comment thread
diogoncalves marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,26 @@ providers:
max_tokens: 100000
input_token_cost: 0.00000163
output_token_cost: 0.00000551
claude-opus-4-6:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000005
output_token_cost: 0.000025
claude-opus-4-7:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000005
output_token_cost: 0.000025
claude-sonnet-4-6:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000003
output_token_cost: 0.000015
claude-haiku-4-5-20251001:
mode: chat
max_tokens: 200000
input_token_cost: 0.000001
output_token_cost: 0.000005
parameters:
temperature:
name: "Temperature"
Expand Down Expand Up @@ -126,6 +146,26 @@ providers:
max_tokens: 100000
input_token_cost: 0.000008
output_token_cost: 0.000024
anthropic.claude-opus-4-6:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000005
output_token_cost: 0.000025
anthropic.claude-opus-4-7:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000005
output_token_cost: 0.000025
anthropic.claude-sonnet-4-6:
mode: chat
max_tokens: 1000000
input_token_cost: 0.000003
output_token_cost: 0.000015
anthropic.claude-haiku-4-5-20251001-v1:0:
mode: chat
max_tokens: 200000
input_token_cost: 0.000001
output_token_cost: 0.000005
us.amazon.nova-pro-v1:0:
mode: chat
max_tokens: 300000
Expand Down
17 changes: 11 additions & 6 deletions libs/core/llmstudio_core/providers/bedrock_converse.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,17 +335,22 @@ def _process_messages(
return messages, system_prompt

@staticmethod
def _base64_to_bytes(image_url: str) -> bytes:
def _b64_data_url_to_bytes(b64_data_url: str) -> bytes:
"""
Extracts and decodes Base64 image data from a 'data:image/...;base64,...' URL.
Extracts and decodes Base64 image data from a 'data:image/...;base64,...' data URL.
Returns the raw image bytes.
"""
if not image_url.startswith("data:image/"):
if not b64_data_url.startswith("data:image/"):
raise ValueError("Invalid Base64 image URL")

base64_data = re.sub(r"^data:image/[^;]+;base64,", "", image_url)
base64_data = re.sub(r"^data:image/[^;]+;base64,", "", b64_data_url)

return base64.b64decode(base64_data)
try:
return base64.b64decode(base64_data)
except Exception as e:
raise ValueError(
f"Failed to decode Base64: {e} ; For Base64 Data Url: {b64_data_url}"
)

@staticmethod
def _get_img_format_from_bytes(image_bytes: bytes) -> str:
Expand Down Expand Up @@ -377,7 +382,7 @@ def _get_image_bytes(image_url: str) -> bytes:
- If it's a normal URL, downloads and encodes the image in Base64.
"""
if image_url.startswith("data:image/"):
return BedrockConverseProvider._base64_to_bytes(image_url)
return BedrockConverseProvider._b64_data_url_to_bytes(image_url)

elif image_url.startswith(("http://", "https://")):
response = requests.get(image_url)
Expand Down
Loading
Loading