From e1504aa440b0526d8b2061fdb838a8b77a8bab91 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Wed, 17 Dec 2025 21:30:48 +0100 Subject: [PATCH 01/16] feat: REL-10782 Introduce server-ai and langchain packages with initial configurations --- .github/actions/build/action.yml | 3 +- .github/workflows/ci.yml | 4 +- .release-please-manifest.json | 3 +- Makefile | 56 +++++++++++--- docs/conf.py | 3 +- ldai/testing/__init__.py | 0 .../server-ai-langchain/README.md | 31 ++++++++ .../server-ai-langchain/pyproject.toml | 51 +++++++++++++ .../src/ldai_langchain/__init__.py | 14 ++++ .../server-ai-langchain/tests/__init__.py | 1 + packages/sdk/server-ai/README.md | 50 +++++++++++++ packages/sdk/server-ai/pyproject.toml | 70 +++++++++++++++++ .../sdk/server-ai/src/ldai}/__init__.py | 0 .../sdk/server-ai/src/ldai}/chat/__init__.py | 0 .../sdk/server-ai/src/ldai}/client.py | 0 .../sdk/server-ai/src/ldai}/judge/__init__.py | 0 .../ldai}/judge/evaluation_schema_builder.py | 0 .../sdk/server-ai/src/ldai}/models.py | 0 .../server-ai/src/ldai}/providers/__init__.py | 0 .../src/ldai}/providers/ai_provider.py | 0 .../ldai}/providers/ai_provider_factory.py | 0 .../server-ai/src/ldai}/providers/types.py | 0 .../sdk/server-ai/src/ldai}/tracker.py | 0 packages/sdk/server-ai/tests/__init__.py | 1 + .../sdk/server-ai/tests}/test_agents.py | 0 .../sdk/server-ai/tests}/test_model_config.py | 0 .../sdk/server-ai/tests}/test_tracker.py | 0 pyproject.toml | 75 ++++--------------- release-please-config.json | 16 +++- setup.cfg | 2 - 30 files changed, 297 insertions(+), 83 deletions(-) delete mode 100644 ldai/testing/__init__.py create mode 100644 packages/ai-providers/server-ai-langchain/README.md create mode 100644 packages/ai-providers/server-ai-langchain/pyproject.toml create mode 100644 packages/ai-providers/server-ai-langchain/src/ldai_langchain/__init__.py create mode 100644 packages/ai-providers/server-ai-langchain/tests/__init__.py create mode 100644 packages/sdk/server-ai/README.md create mode 100644 packages/sdk/server-ai/pyproject.toml rename {ldai => packages/sdk/server-ai/src/ldai}/__init__.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/chat/__init__.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/client.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/judge/__init__.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/judge/evaluation_schema_builder.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/models.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/providers/__init__.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/providers/ai_provider.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/providers/ai_provider_factory.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/providers/types.py (100%) rename {ldai => packages/sdk/server-ai/src/ldai}/tracker.py (100%) create mode 100644 packages/sdk/server-ai/tests/__init__.py rename {ldai/testing => packages/sdk/server-ai/tests}/test_agents.py (100%) rename {ldai/testing => packages/sdk/server-ai/tests}/test_model_config.py (100%) rename {ldai/testing => packages/sdk/server-ai/tests}/test_tracker.py (100%) delete mode 100644 setup.cfg diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 6761d0d..9fcff44 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -10,10 +10,11 @@ runs: steps: - name: Build distribution files shell: bash + working-directory: ./packages/sdk/server-ai run: poetry build - name: Hash build files for provenance id: package-hashes shell: bash - working-directory: ./dist + working-directory: ./packages/sdk/server-ai/dist run: | echo "package-hashes=$(sha256sum * | base64 -w0)" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd8c2dc..f0fcea8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,9 @@ jobs: uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 - name: Install requirements - run: poetry install + run: | + cd packages/sdk/server-ai + poetry install - name: Run tests run: make test diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 30b6d45..7c26fcf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,4 @@ { - ".": "0.10.1" + "packages/sdk/server-ai": "0.10.1", + "packages/ai-providers/server-ai-langchain": "0.1.0" } diff --git a/Makefile b/Makefile index 791925c..c2ed931 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ SPHINXPROJ = launchdarkly-server-sdk SOURCEDIR = docs BUILDDIR = $(SOURCEDIR)/build +# Package paths +SERVER_AI_PKG = packages/sdk/server-ai +LANGCHAIN_PKG = packages/ai-providers/server-ai-langchain + .PHONY: help help: #! Show this help message @echo 'Usage: make [target] ... ' @@ -14,24 +18,52 @@ help: #! Show this help message @grep -h -F '#!' $(MAKEFILE_LIST) | grep -v grep | sed 's/:.*#!/:/' | column -t -s":" .PHONY: install -install: - @poetry install +install: #! Install all packages + @cd $(SERVER_AI_PKG) && poetry install + @cd $(LANGCHAIN_PKG) && poetry install + +.PHONY: install-server-ai +install-server-ai: #! Install server-ai package + @cd $(SERVER_AI_PKG) && poetry install + +.PHONY: install-langchain +install-langchain: #! Install langchain provider package + @cd $(LANGCHAIN_PKG) && poetry install # # Quality control checks # .PHONY: test -test: #! Run unit tests -test: install - @poetry run pytest $(PYTEST_FLAGS) +test: #! Run unit tests for all packages +test: test-server-ai + +.PHONY: test-server-ai +test-server-ai: #! Run unit tests for server-ai package +test-server-ai: install-server-ai + @cd $(SERVER_AI_PKG) && poetry run pytest $(PYTEST_FLAGS) + +.PHONY: test-langchain +test-langchain: #! Run unit tests for langchain provider package +test-langchain: install-langchain + @cd $(LANGCHAIN_PKG) && poetry run pytest $(PYTEST_FLAGS) .PHONY: lint -lint: #! Run type analysis and linting checks -lint: install - @poetry run mypy ldai - @poetry run isort --check --atomic ldai - @poetry run pycodestyle ldai +lint: #! Run type analysis and linting checks for all packages +lint: lint-server-ai + +.PHONY: lint-server-ai +lint-server-ai: #! Run type analysis and linting checks for server-ai package +lint-server-ai: install-server-ai + @cd $(SERVER_AI_PKG) && poetry run mypy src/ldai + @cd $(SERVER_AI_PKG) && poetry run isort --check --atomic src/ldai + @cd $(SERVER_AI_PKG) && poetry run pycodestyle src/ldai + +.PHONY: lint-langchain +lint-langchain: #! Run type analysis and linting checks for langchain provider package +lint-langchain: install-langchain + @cd $(LANGCHAIN_PKG) && poetry run mypy src/ldai_langchain + @cd $(LANGCHAIN_PKG) && poetry run pycodestyle src/ldai_langchain # # Documentation generation @@ -39,6 +71,6 @@ lint: install .PHONY: docs docs: #! Generate sphinx-based documentation - @poetry install --with docs + @cd $(SERVER_AI_PKG) && poetry install --with docs @cd docs - @poetry run $(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @cd $(SERVER_AI_PKG) && poetry run $(SPHINXBUILD) -M html "../../../$(SOURCEDIR)" "../../../$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 20ca389..47061f1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,7 +19,8 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) +# Add the server-ai package source to the path +sys.path.insert(0, os.path.abspath('../packages/sdk/server-ai/src')) import ldai diff --git a/ldai/testing/__init__.py b/ldai/testing/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/packages/ai-providers/server-ai-langchain/README.md b/packages/ai-providers/server-ai-langchain/README.md new file mode 100644 index 0000000..f612c63 --- /dev/null +++ b/packages/ai-providers/server-ai-langchain/README.md @@ -0,0 +1,31 @@ +# LaunchDarkly AI SDK - LangChain Provider + +This package provides LangChain integration for the LaunchDarkly Server-Side AI SDK. + +## Status + +🚧 **Coming Soon** - This package is a placeholder for future LangChain integration. + +## Installation + +```bash +pip install launchdarkly-server-sdk-ai-langchain +``` + +## Usage + +```python +# Coming soon +``` + +## Documentation + +For full documentation, please refer to the [LaunchDarkly AI SDK documentation](https://docs.launchdarkly.com/sdk/ai/python). + +## Contributing + +See [CONTRIBUTING.md](../../../CONTRIBUTING.md) in the repository root. + +## License + +Apache-2.0 diff --git a/packages/ai-providers/server-ai-langchain/pyproject.toml b/packages/ai-providers/server-ai-langchain/pyproject.toml new file mode 100644 index 0000000..db792e1 --- /dev/null +++ b/packages/ai-providers/server-ai-langchain/pyproject.toml @@ -0,0 +1,51 @@ +[tool.poetry] +name = "launchdarkly-server-sdk-ai-langchain" +version = "0.1.0" +description = "LaunchDarkly AI SDK LangChain Provider" +authors = ["LaunchDarkly "] +license = "Apache-2.0" +readme = "README.md" +homepage = "https://docs.launchdarkly.com/sdk/ai/python" +repository = "https://github.com/launchdarkly/python-server-sdk-ai" +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", +] +packages = [{ include = "ldai_langchain", from = "src" }] + +[tool.poetry.dependencies] +python = ">=3.9,<4" +launchdarkly-server-sdk-ai = ">=0.10.1" +# langchain-core = ">=0.1.0" # Uncomment when implementing + + +[tool.poetry.group.dev.dependencies] +pytest = ">=2.8" +pytest-cov = ">=2.4.0" +pytest-asyncio = ">=0.21.0" +mypy = "==1.18.2" + +[tool.mypy] +python_version = "3.9" +ignore_missing_imports = true +install_types = true +non_interactive = true + + +[tool.pytest.ini_options] +addopts = ["-ra"] +testpaths = ["tests"] + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/packages/ai-providers/server-ai-langchain/src/ldai_langchain/__init__.py b/packages/ai-providers/server-ai-langchain/src/ldai_langchain/__init__.py new file mode 100644 index 0000000..bf15780 --- /dev/null +++ b/packages/ai-providers/server-ai-langchain/src/ldai_langchain/__init__.py @@ -0,0 +1,14 @@ +"""LaunchDarkly AI SDK - LangChain Provider. + +This package provides LangChain integration for the LaunchDarkly Server-Side AI SDK. +""" + +__version__ = "0.1.0" + +# Placeholder for future LangChain provider implementation +# from ldai_langchain.langchain_provider import LangChainProvider + +__all__ = [ + '__version__', + # 'LangChainProvider', # Uncomment when implemented +] diff --git a/packages/ai-providers/server-ai-langchain/tests/__init__.py b/packages/ai-providers/server-ai-langchain/tests/__init__.py new file mode 100644 index 0000000..c76e4c7 --- /dev/null +++ b/packages/ai-providers/server-ai-langchain/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for LangChain provider.""" diff --git a/packages/sdk/server-ai/README.md b/packages/sdk/server-ai/README.md new file mode 100644 index 0000000..acd05d2 --- /dev/null +++ b/packages/sdk/server-ai/README.md @@ -0,0 +1,50 @@ +# LaunchDarkly Server-Side AI SDK for Python + +This package contains the LaunchDarkly Server-Side AI SDK for Python (`launchdarkly-server-sdk-ai`). + +## Installation + +```bash +pip install launchdarkly-server-sdk-ai +``` + +## Quick Start + +```python +from ldclient import LDClient, Config, Context +from ldai import LDAIClient, AICompletionConfigDefault, ModelConfig + +# Initialize LaunchDarkly client +ld_client = LDClient(Config("your-sdk-key")) + +# Create AI client +ai_client = LDAIClient(ld_client) + +# Get AI configuration +context = Context.create("user-123") +config = ai_client.completion_config( + "my-ai-config", + context, + AICompletionConfigDefault( + enabled=True, + model=ModelConfig("gpt-4") + ) +) + +# Use the configuration with your AI provider +if config.enabled: + # Your AI implementation here + pass +``` + +## Documentation + +For full documentation, please refer to the [LaunchDarkly AI SDK documentation](https://docs.launchdarkly.com/sdk/ai/python). + +## Contributing + +See [CONTRIBUTING.md](../../../CONTRIBUTING.md) in the repository root. + +## License + +Apache-2.0 diff --git a/packages/sdk/server-ai/pyproject.toml b/packages/sdk/server-ai/pyproject.toml new file mode 100644 index 0000000..426d93b --- /dev/null +++ b/packages/sdk/server-ai/pyproject.toml @@ -0,0 +1,70 @@ +[tool.poetry] +name = "launchdarkly-server-sdk-ai" +version = "0.10.1" +description = "LaunchDarkly SDK for AI" +authors = ["LaunchDarkly "] +license = "Apache-2.0" +readme = "README.md" +homepage = "https://docs.launchdarkly.com/sdk/ai/python" +repository = "https://github.com/launchdarkly/python-server-sdk-ai" +documentation = "https://launchdarkly-python-sdk-ai.readthedocs.io/en/latest/" +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", +] +packages = [{ include = "ldai", from = "src" }] + +[tool.poetry.dependencies] +python = ">=3.9,<4" +launchdarkly-server-sdk = ">=9.4.0" +chevron = "=0.14.0" + + +[tool.poetry.group.dev.dependencies] +pytest = ">=2.8" +pytest-cov = ">=2.4.0" +pytest-mypy = "==1.0.1" +pytest-asyncio = ">=0.21.0" +mypy = "==1.18.2" +pycodestyle = "^2.12.1" +isort = ">=5.13.2,<7.0.0" + + +[tool.poetry.group.docs] +optional = true + +[tool.poetry.group.docs.dependencies] +sphinx = ">=6,<8" +sphinx-rtd-theme = ">=1.3,<4.0" +certifi = ">=2018.4.16" +expiringdict = ">=1.1.4" +pyrfc3339 = ">=1.0" +jsonpickle = ">1.4.1" +semver = ">=2.7.9" +urllib3 = ">=1.26.0" +jinja2 = "3.1.6" + +[tool.mypy] +python_version = "3.9" +ignore_missing_imports = true +install_types = true +non_interactive = true + + +[tool.pytest.ini_options] +addopts = ["-ra"] +testpaths = ["tests"] + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/ldai/__init__.py b/packages/sdk/server-ai/src/ldai/__init__.py similarity index 100% rename from ldai/__init__.py rename to packages/sdk/server-ai/src/ldai/__init__.py diff --git a/ldai/chat/__init__.py b/packages/sdk/server-ai/src/ldai/chat/__init__.py similarity index 100% rename from ldai/chat/__init__.py rename to packages/sdk/server-ai/src/ldai/chat/__init__.py diff --git a/ldai/client.py b/packages/sdk/server-ai/src/ldai/client.py similarity index 100% rename from ldai/client.py rename to packages/sdk/server-ai/src/ldai/client.py diff --git a/ldai/judge/__init__.py b/packages/sdk/server-ai/src/ldai/judge/__init__.py similarity index 100% rename from ldai/judge/__init__.py rename to packages/sdk/server-ai/src/ldai/judge/__init__.py diff --git a/ldai/judge/evaluation_schema_builder.py b/packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py similarity index 100% rename from ldai/judge/evaluation_schema_builder.py rename to packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py diff --git a/ldai/models.py b/packages/sdk/server-ai/src/ldai/models.py similarity index 100% rename from ldai/models.py rename to packages/sdk/server-ai/src/ldai/models.py diff --git a/ldai/providers/__init__.py b/packages/sdk/server-ai/src/ldai/providers/__init__.py similarity index 100% rename from ldai/providers/__init__.py rename to packages/sdk/server-ai/src/ldai/providers/__init__.py diff --git a/ldai/providers/ai_provider.py b/packages/sdk/server-ai/src/ldai/providers/ai_provider.py similarity index 100% rename from ldai/providers/ai_provider.py rename to packages/sdk/server-ai/src/ldai/providers/ai_provider.py diff --git a/ldai/providers/ai_provider_factory.py b/packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py similarity index 100% rename from ldai/providers/ai_provider_factory.py rename to packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py diff --git a/ldai/providers/types.py b/packages/sdk/server-ai/src/ldai/providers/types.py similarity index 100% rename from ldai/providers/types.py rename to packages/sdk/server-ai/src/ldai/providers/types.py diff --git a/ldai/tracker.py b/packages/sdk/server-ai/src/ldai/tracker.py similarity index 100% rename from ldai/tracker.py rename to packages/sdk/server-ai/src/ldai/tracker.py diff --git a/packages/sdk/server-ai/tests/__init__.py b/packages/sdk/server-ai/tests/__init__.py new file mode 100644 index 0000000..1ea3607 --- /dev/null +++ b/packages/sdk/server-ai/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for the LaunchDarkly Server-Side AI SDK.""" diff --git a/ldai/testing/test_agents.py b/packages/sdk/server-ai/tests/test_agents.py similarity index 100% rename from ldai/testing/test_agents.py rename to packages/sdk/server-ai/tests/test_agents.py diff --git a/ldai/testing/test_model_config.py b/packages/sdk/server-ai/tests/test_model_config.py similarity index 100% rename from ldai/testing/test_model_config.py rename to packages/sdk/server-ai/tests/test_model_config.py diff --git a/ldai/testing/test_tracker.py b/packages/sdk/server-ai/tests/test_tracker.py similarity index 100% rename from ldai/testing/test_tracker.py rename to packages/sdk/server-ai/tests/test_tracker.py diff --git a/pyproject.toml b/pyproject.toml index 9c1f44a..a38cffc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,71 +1,22 @@ +# Root pyproject.toml for the LaunchDarkly Python AI SDK monorepo +# +# This monorepo contains: +# - packages/sdk/server-ai: The main LaunchDarkly Server-Side AI SDK +# - packages/ai-providers/server-ai-langchain: LangChain integration (placeholder) +# +# For development, use the package-specific pyproject.toml files in: +# - packages/sdk/server-ai/pyproject.toml +# - packages/ai-providers/server-ai-langchain/pyproject.toml + [tool.poetry] -name = "launchdarkly-server-sdk-ai" -version = "0.10.1" -description = "LaunchDarkly SDK for AI" +name = "launchdarkly-python-sdk-ai-monorepo" +version = "0.0.0" +description = "LaunchDarkly Python AI SDK Monorepo" authors = ["LaunchDarkly "] license = "Apache-2.0" -readme = "README.md" -homepage = "https://docs.launchdarkly.com/sdk/ai/python" -repository = "https://github.com/launchdarkly/python-server-sdk-ai" -documentation = "https://launchdarkly-python-sdk-ai.readthedocs.io/en/latest/" -classifiers = [ - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Topic :: Software Development", - "Topic :: Software Development :: Libraries", -] -packages = [ { include = "ldai" } ] -exclude = [ - { path = "ldai/testing", format = "wheel" } -] [tool.poetry.dependencies] python = ">=3.9,<4" -launchdarkly-server-sdk = ">=9.4.0" -chevron = "=0.14.0" - - -[tool.poetry.group.dev.dependencies] -pytest = ">=2.8" -pytest-cov = ">=2.4.0" -pytest-mypy = "==1.0.1" -pytest-asyncio = ">=0.21.0" -mypy = "==1.18.2" -pycodestyle = "^2.12.1" -isort = ">=5.13.2,<7.0.0" - - -[tool.poetry.group.docs] -optional = true - -[tool.poetry.group.docs.dependencies] -sphinx = ">=6,<8" -sphinx-rtd-theme = ">=1.3,<4.0" -certifi = ">=2018.4.16" -expiringdict = ">=1.1.4" -pyrfc3339 = ">=1.0" -jsonpickle = ">1.4.1" -semver = ">=2.7.9" -urllib3 = ">=1.26.0" -jinja2 = "3.1.6" - -[tool.mypy] -python_version = "3.9" -ignore_missing_imports = true -install_types = true -non_interactive = true - - -[tool.pytest.ini_options] -addopts = ["-ra"] - [build-system] requires = ["poetry-core"] diff --git a/release-please-config.json b/release-please-config.json index 78df6d7..4b8a2d2 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,12 +1,22 @@ { "packages": { - ".": { + "packages/sdk/server-ai": { "release-type": "python", "versioning": "default", "bump-minor-pre-major": true, "include-v-in-tag": false, - "extra-files": ["ldai/__init__.py", "PROVENANCE.md"], - "include-component-in-tag": false + "extra-files": ["src/ldai/__init__.py", "../../../PROVENANCE.md"], + "include-component-in-tag": true, + "component": "server-ai" + }, + "packages/ai-providers/server-ai-langchain": { + "release-type": "python", + "versioning": "default", + "bump-minor-pre-major": true, + "include-v-in-tag": false, + "extra-files": ["src/ldai_langchain/__init__.py"], + "include-component-in-tag": true, + "component": "server-ai-langchain" } } } diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1fb1827..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[pycodestyle] -ignore = E501,W503 From 394f10026287d9d89e04eca9cce074037b2df236 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Wed, 17 Dec 2025 21:31:14 +0100 Subject: [PATCH 02/16] refactor: Update Makefile to streamline installation, testing, and linting processes --- .github/actions/build-docs/action.yml | 7 +- .github/actions/build/action.yml | 12 +- .github/actions/ci/action.yml | 34 ++++ .github/workflows/ci.yml | 32 ++-- .github/workflows/release-please.yml | 161 ++++++++++++++---- Makefile | 51 +++--- .../ai-providers/server-ai-langchain/Makefile | 28 +++ packages/sdk/server-ai/Makefile | 40 +++++ 8 files changed, 290 insertions(+), 75 deletions(-) create mode 100644 .github/actions/ci/action.yml create mode 100644 packages/ai-providers/server-ai-langchain/Makefile create mode 100644 packages/sdk/server-ai/Makefile diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml index 84e6a1b..0ef8929 100644 --- a/.github/actions/build-docs/action.yml +++ b/.github/actions/build-docs/action.yml @@ -1,5 +1,10 @@ name: Build Documentation -description: 'Build Documentation.' +description: 'Build Documentation for a package' +inputs: + workspace_path: + description: 'Path to the package to build docs for.' + required: false + default: 'packages/sdk/server-ai' runs: using: composite diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 9fcff44..d096f3c 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -1,5 +1,9 @@ name: Build distribution files -description: 'Build distribution files' +description: 'Build distribution files for a package' +inputs: + workspace_path: + description: 'Path to the package to build.' + required: true outputs: package-hashes: description: "base64-encoded sha256 hashes of distribution files" @@ -10,11 +14,11 @@ runs: steps: - name: Build distribution files shell: bash - working-directory: ./packages/sdk/server-ai - run: poetry build + run: make -C ${{ inputs.workspace_path }} build + - name: Hash build files for provenance id: package-hashes shell: bash - working-directory: ./packages/sdk/server-ai/dist + working-directory: ${{ inputs.workspace_path }}/dist run: | echo "package-hashes=$(sha256sum * | base64 -w0)" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml new file mode 100644 index 0000000..e744ef6 --- /dev/null +++ b/.github/actions/ci/action.yml @@ -0,0 +1,34 @@ +name: Shared CI Workflow +description: 'Build, lint, and test a package' +inputs: + workspace_path: + description: 'Path to the package to build/test.' + required: true + python_version: + description: 'Python version to use' + required: false + default: '3.11' + +runs: + using: composite + steps: + - name: Set up Python ${{ inputs.python_version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Install poetry + uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 + + - name: Install Dependencies + shell: bash + working-directory: ${{ inputs.workspace_path }} + run: poetry install + + - name: Lint + shell: bash + run: make -C ${{ inputs.workspace_path }} lint + + - name: Test + shell: bash + run: make -C ${{ inputs.workspace_path }} test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0fcea8..d376c8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,35 +11,31 @@ on: - '**.md' jobs: - linux: + server-ai-linux: runs-on: ubuntu-latest - strategy: matrix: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - name: Install poetry uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 - - uses: ./.github/actions/build - - uses: ./.github/actions/build-docs + - uses: ./.github/actions/ci + with: + workspace_path: packages/sdk/server-ai + python_version: ${{ matrix.python-version }} - - name: Run tests - run: make test + - uses: ./.github/actions/build + with: + workspace_path: packages/sdk/server-ai - - name: Verify typehints - run: make lint + - uses: ./.github/actions/build-docs - windows: + server-ai-windows: runs-on: windows-latest - defaults: run: shell: powershell @@ -50,6 +46,7 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: @@ -59,9 +56,8 @@ jobs: uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 - name: Install requirements - run: | - cd packages/sdk/server-ai - poetry install + working-directory: packages/sdk/server-ai + run: poetry install - name: Run tests - run: make test + run: make -C packages/sdk/server-ai test diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 7176356..d1fdeee 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,67 +1,164 @@ -name: Run Release Please +# This workflow handles both automated and manual package publishing: +# +# AUTOMATED PUBLISHING (on push to main): +# - Triggered automatically when changes are pushed to the main branch +# - Uses release-please to create releases based on conventional commits +# - Publishes packages to PyPI automatically when release PRs are merged +# +# MANUAL PUBLISHING (via workflow_dispatch): +# - Can be triggered manually from the Actions tab +# - Allows publishing a specific package to PyPI +# - Supports dry-run mode +# +name: release-please on: push: - branches: [ main ] + branches: + - main + workflow_dispatch: + inputs: + workspace_path: + description: 'The workspace to publish' + required: true + default: 'packages/sdk/server-ai' + type: choice + options: + - packages/sdk/server-ai + - packages/ai-providers/server-ai-langchain + dry_run: + description: 'Is this a dry run. If so no package will be published.' + type: boolean + required: true jobs: - release-package: + release-please: runs-on: ubuntu-latest - permissions: - id-token: write # Needed if using OIDC to get release secrets. - contents: write # Contents and pull-requests are for release-please to make releases. - pull-requests: write + if: github.event_name == 'push' outputs: - release-created: ${{ steps.release.outputs.release_created }} - upload-tag-name: ${{ steps.release.outputs.tag_name }} - package-hashes: ${{ steps.build.outputs.package-hashes}} + package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }} + package-server-ai-langchain-released: ${{ steps.release.outputs['packages/ai-providers/server-ai-langchain--release_created'] }} steps: - uses: googleapis/release-please-action@v4 id: release + with: + token: ${{secrets.GITHUB_TOKEN}} + release-server-ai: + runs-on: ubuntu-latest + needs: ['release-please'] + permissions: + id-token: write + contents: write + if: ${{ needs.release-please.outputs.package-server-ai-released == 'true' }} + steps: - uses: actions/checkout@v4 - if: ${{ steps.release.outputs.releases_created == 'true' }} with: - fetch-depth: 0 # If you only need the current version keep this. + fetch-depth: 0 - uses: actions/setup-python@v5 - if: ${{ steps.release.outputs.releases_created == 'true' }} with: - python-version: 3.9 + python-version: '3.11' - name: Install poetry - if: ${{ steps.release.outputs.releases_created == 'true' }} uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 + - uses: ./.github/actions/ci + with: + workspace_path: packages/sdk/server-ai + + - uses: ./.github/actions/build + id: build + with: + workspace_path: packages/sdk/server-ai + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 - if: ${{ steps.release.outputs.releases_created == 'true' }} name: 'Get PyPI token' with: aws_assume_role: ${{ vars.AWS_ROLE_ARN }} ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN' + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ env.PYPI_AUTH_TOKEN }} + packages-dir: packages/sdk/server-ai/dist/ + + release-server-ai-langchain: + runs-on: ubuntu-latest + needs: ['release-please', 'release-server-ai'] + permissions: + id-token: write + contents: write + if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install poetry + uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 + + - uses: ./.github/actions/ci + with: + workspace_path: packages/ai-providers/server-ai-langchain + - uses: ./.github/actions/build id: build - if: ${{ steps.release.outputs.releases_created == 'true' }} + with: + workspace_path: packages/ai-providers/server-ai-langchain - - uses: ./.github/actions/build-docs - if: ${{ steps.release.outputs.releases_created == 'true' }} + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 + name: 'Get PyPI token' + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN' - - name: Publish package distributions to PyPI - if: ${{ steps.release.outputs.releases_created == 'true' }} + - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - password: ${{env.PYPI_AUTH_TOKEN}} + password: ${{ env.PYPI_AUTH_TOKEN }} + packages-dir: packages/ai-providers/server-ai-langchain/dist/ - release-provenance: - needs: [ 'release-package' ] - if: ${{ needs.release-package.outputs.release-created == 'true' }} + manual-publish: + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' permissions: - actions: read id-token: write - contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 - with: - base64-subjects: "${{ needs.release-package.outputs.package-hashes }}" - upload-assets: true - upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }} + contents: read + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install poetry + uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 + + - uses: ./.github/actions/ci + with: + workspace_path: ${{ inputs.workspace_path }} + + - uses: ./.github/actions/build + id: build + with: + workspace_path: ${{ inputs.workspace_path }} + + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 + if: ${{ inputs.dry_run != true }} + name: 'Get PyPI token' + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN' + + - name: Publish to PyPI + if: ${{ inputs.dry_run != true }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ env.PYPI_AUTH_TOKEN }} + packages-dir: ${{ inputs.workspace_path }}/dist/ diff --git a/Makefile b/Makefile index c2ed931..31de23e 100644 --- a/Makefile +++ b/Makefile @@ -17,18 +17,22 @@ help: #! Show this help message @echo 'Targets:' @grep -h -F '#!' $(MAKEFILE_LIST) | grep -v grep | sed 's/:.*#!/:/' | column -t -s":" +# +# Installation targets +# + .PHONY: install install: #! Install all packages - @cd $(SERVER_AI_PKG) && poetry install - @cd $(LANGCHAIN_PKG) && poetry install + $(MAKE) -C $(SERVER_AI_PKG) install + $(MAKE) -C $(LANGCHAIN_PKG) install .PHONY: install-server-ai install-server-ai: #! Install server-ai package - @cd $(SERVER_AI_PKG) && poetry install + $(MAKE) -C $(SERVER_AI_PKG) install .PHONY: install-langchain install-langchain: #! Install langchain provider package - @cd $(LANGCHAIN_PKG) && poetry install + $(MAKE) -C $(LANGCHAIN_PKG) install # # Quality control checks @@ -36,34 +40,43 @@ install-langchain: #! Install langchain provider package .PHONY: test test: #! Run unit tests for all packages -test: test-server-ai + $(MAKE) -C $(SERVER_AI_PKG) test .PHONY: test-server-ai test-server-ai: #! Run unit tests for server-ai package -test-server-ai: install-server-ai - @cd $(SERVER_AI_PKG) && poetry run pytest $(PYTEST_FLAGS) + $(MAKE) -C $(SERVER_AI_PKG) test .PHONY: test-langchain test-langchain: #! Run unit tests for langchain provider package -test-langchain: install-langchain - @cd $(LANGCHAIN_PKG) && poetry run pytest $(PYTEST_FLAGS) + $(MAKE) -C $(LANGCHAIN_PKG) test .PHONY: lint lint: #! Run type analysis and linting checks for all packages -lint: lint-server-ai + $(MAKE) -C $(SERVER_AI_PKG) lint .PHONY: lint-server-ai lint-server-ai: #! Run type analysis and linting checks for server-ai package -lint-server-ai: install-server-ai - @cd $(SERVER_AI_PKG) && poetry run mypy src/ldai - @cd $(SERVER_AI_PKG) && poetry run isort --check --atomic src/ldai - @cd $(SERVER_AI_PKG) && poetry run pycodestyle src/ldai + $(MAKE) -C $(SERVER_AI_PKG) lint .PHONY: lint-langchain lint-langchain: #! Run type analysis and linting checks for langchain provider package -lint-langchain: install-langchain - @cd $(LANGCHAIN_PKG) && poetry run mypy src/ldai_langchain - @cd $(LANGCHAIN_PKG) && poetry run pycodestyle src/ldai_langchain + $(MAKE) -C $(LANGCHAIN_PKG) lint + +# +# Build targets +# + +.PHONY: build +build: #! Build all packages + $(MAKE) -C $(SERVER_AI_PKG) build + +.PHONY: build-server-ai +build-server-ai: #! Build server-ai package + $(MAKE) -C $(SERVER_AI_PKG) build + +.PHONY: build-langchain +build-langchain: #! Build langchain provider package + $(MAKE) -C $(LANGCHAIN_PKG) build # # Documentation generation @@ -71,6 +84,4 @@ lint-langchain: install-langchain .PHONY: docs docs: #! Generate sphinx-based documentation - @cd $(SERVER_AI_PKG) && poetry install --with docs - @cd docs - @cd $(SERVER_AI_PKG) && poetry run $(SPHINXBUILD) -M html "../../../$(SOURCEDIR)" "../../../$(BUILDDIR)" $(SPHINXOPTS) $(O) + $(MAKE) -C $(SERVER_AI_PKG) docs DOCS_DIR=../../../$(SOURCEDIR) DOCS_BUILD_DIR=../../../$(BUILDDIR) diff --git a/packages/ai-providers/server-ai-langchain/Makefile b/packages/ai-providers/server-ai-langchain/Makefile new file mode 100644 index 0000000..2486d17 --- /dev/null +++ b/packages/ai-providers/server-ai-langchain/Makefile @@ -0,0 +1,28 @@ +PYTEST_FLAGS=-W error::SyntaxWarning + +.PHONY: help +help: #! Show this help message + @echo 'Usage: make [target] ... ' + @echo '' + @echo 'Targets:' + @grep -h -F '#!' $(MAKEFILE_LIST) | grep -v grep | sed 's/:.*#!/:/' | column -t -s":" + +.PHONY: install +install: #! Install package dependencies + poetry install + +.PHONY: test +test: #! Run unit tests +test: install + poetry run pytest $(PYTEST_FLAGS) + +.PHONY: lint +lint: #! Run type analysis and linting checks +lint: install + poetry run mypy src/ldai_langchain + poetry run pycodestyle src/ldai_langchain + +.PHONY: build +build: #! Build distribution files +build: install + poetry build diff --git a/packages/sdk/server-ai/Makefile b/packages/sdk/server-ai/Makefile new file mode 100644 index 0000000..95f037c --- /dev/null +++ b/packages/sdk/server-ai/Makefile @@ -0,0 +1,40 @@ +PYTEST_FLAGS=-W error::SyntaxWarning +SPHINXOPTS = -W --keep-going +SPHINXBUILD = sphinx-build + +# Configurable docs paths (can be overridden from root Makefile) +DOCS_DIR ?= docs +DOCS_BUILD_DIR ?= docs/build + +.PHONY: help +help: #! Show this help message + @echo 'Usage: make [target] ... ' + @echo '' + @echo 'Targets:' + @grep -h -F '#!' $(MAKEFILE_LIST) | grep -v grep | sed 's/:.*#!/:/' | column -t -s":" + +.PHONY: install +install: #! Install package dependencies + poetry install + +.PHONY: test +test: #! Run unit tests +test: install + poetry run pytest $(PYTEST_FLAGS) + +.PHONY: lint +lint: #! Run type analysis and linting checks +lint: install + poetry run mypy src/ldai + poetry run isort --check --atomic src/ldai + poetry run pycodestyle src/ldai + +.PHONY: build +build: #! Build distribution files +build: install + poetry build + +.PHONY: docs +docs: #! Generate sphinx-based documentation + poetry install --with docs + poetry run $(SPHINXBUILD) -M html "$(DOCS_DIR)" "$(DOCS_BUILD_DIR)" $(SPHINXOPTS) From 73396ab308e4a6ebbee509aa96809ca1cad0e70a Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Wed, 17 Dec 2025 21:44:13 +0100 Subject: [PATCH 03/16] linting --- packages/sdk/server-ai/setup.cfg | 2 ++ packages/sdk/server-ai/src/ldai/client.py | 5 ++++- .../server-ai/src/ldai/judge/evaluation_schema_builder.py | 5 ++++- .../sdk/server-ai/src/ldai/providers/ai_provider_factory.py | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 packages/sdk/server-ai/setup.cfg diff --git a/packages/sdk/server-ai/setup.cfg b/packages/sdk/server-ai/setup.cfg new file mode 100644 index 0000000..6224f31 --- /dev/null +++ b/packages/sdk/server-ai/setup.cfg @@ -0,0 +1,2 @@ +[pycodestyle] +max-line-length = 120 diff --git a/packages/sdk/server-ai/src/ldai/client.py b/packages/sdk/server-ai/src/ldai/client.py index ea07915..986be3d 100644 --- a/packages/sdk/server-ai/src/ldai/client.py +++ b/packages/sdk/server-ai/src/ldai/client.py @@ -444,7 +444,10 @@ def __evaluate( context: Context, default_dict: Dict[str, Any], variables: Optional[Dict[str, Any]] = None, - ) -> Tuple[Optional[ModelConfig], Optional[ProviderConfig], Optional[List[LDMessage]], Optional[str], LDAIConfigTracker, bool, Optional[Any]]: + ) -> Tuple[ + Optional[ModelConfig], Optional[ProviderConfig], Optional[List[LDMessage]], + Optional[str], LDAIConfigTracker, bool, Optional[Any] + ]: """ Internal method to evaluate a configuration and extract components. diff --git a/packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py b/packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py index c996f08..29b885d 100644 --- a/packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py +++ b/packages/sdk/server-ai/src/ldai/judge/evaluation_schema_builder.py @@ -24,7 +24,10 @@ def build(evaluation_metric_keys: list[str]) -> Dict[str, Any]: 'properties': { 'evaluations': { 'type': 'object', - 'description': f"Object containing evaluation results for {', '.join(evaluation_metric_keys)} metrics", + 'description': ( + f"Object containing evaluation results for " + f"{', '.join(evaluation_metric_keys)} metrics" + ), 'properties': EvaluationSchemaBuilder._build_key_properties(evaluation_metric_keys), 'required': evaluation_metric_keys, 'additionalProperties': False, diff --git a/packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py b/packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py index 3fd0f50..7419176 100644 --- a/packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py +++ b/packages/sdk/server-ai/src/ldai/providers/ai_provider_factory.py @@ -156,8 +156,9 @@ async def _create_provider( provider = await provider_class.create(ai_config, logger) if logger: + provider_name = ai_config.provider.name if ai_config.provider else 'unknown' logger.debug( - f"Successfully created AIProvider for: {ai_config.provider.name if ai_config.provider else 'unknown'} " + f"Successfully created AIProvider for: {provider_name} " f"with package {package_name}" ) return provider From db0debd36659651937b67521a9d9c3a596edabb0 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:05:33 +0100 Subject: [PATCH 04/16] support building docs for different packages --- .github/actions/build-docs/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml index 0ef8929..3c5efc3 100644 --- a/.github/actions/build-docs/action.yml +++ b/.github/actions/build-docs/action.yml @@ -11,4 +11,5 @@ runs: steps: - name: Build Documentation shell: bash + working-directory: ${{ inputs.workspace_path }} run: make docs From d058cb7d4d6981912be672a43285a8f9a1453596 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:08:30 +0100 Subject: [PATCH 05/16] remove redundant step from ci --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d376c8f..d1980dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,9 +20,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install poetry - uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 - - uses: ./.github/actions/ci with: workspace_path: packages/sdk/server-ai From f634a5446dd612abe66976a650150f2a834fb6b5 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:10:34 +0100 Subject: [PATCH 06/16] add back write permission to release please --- .github/workflows/release-please.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index d1fdeee..ea86e46 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -34,6 +34,9 @@ on: jobs: release-please: runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write if: github.event_name == 'push' outputs: package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }} From 5d269b5644f6384c65f84491953382e84e6e7fdf Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:12:33 +0100 Subject: [PATCH 07/16] Remove token configuration from release-please workflow --- .github/workflows/release-please.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index ea86e46..178168a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -44,8 +44,6 @@ jobs: steps: - uses: googleapis/release-please-action@v4 id: release - with: - token: ${{secrets.GITHUB_TOKEN}} release-server-ai: runs-on: ubuntu-latest From 2304a9b9a81f0e16faac641301a5cb735a3fa7b6 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:14:23 +0100 Subject: [PATCH 08/16] Update release-server-ai-langchain dependencies to remove unnecessary job dependencies --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 178168a..34ada06 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -87,7 +87,7 @@ jobs: release-server-ai-langchain: runs-on: ubuntu-latest - needs: ['release-please', 'release-server-ai'] + needs: ['release-please'] permissions: id-token: write contents: write From bd6409bc607313da0f700f6d6795ddc0bfe8f134 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:29:07 +0100 Subject: [PATCH 09/16] remove contents: write permission and add back explanatory comments that were lost --- .github/workflows/release-please.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 34ada06..25649e1 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -35,8 +35,8 @@ jobs: release-please: runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: write # Needed for release-please to create releases. + pull-requests: write # Needed for release-please to create/update PRs. if: github.event_name == 'push' outputs: package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }} @@ -49,8 +49,7 @@ jobs: runs-on: ubuntu-latest needs: ['release-please'] permissions: - id-token: write - contents: write + id-token: write # Needed for OIDC to get release secrets from AWS. if: ${{ needs.release-please.outputs.package-server-ai-released == 'true' }} steps: - uses: actions/checkout@v4 @@ -89,8 +88,7 @@ jobs: runs-on: ubuntu-latest needs: ['release-please'] permissions: - id-token: write - contents: write + id-token: write # Needed for OIDC to get release secrets from AWS. if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} steps: - uses: actions/checkout@v4 @@ -129,8 +127,8 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' permissions: - id-token: write - contents: read + id-token: write # Needed for OIDC to get release secrets from AWS. + contents: read # Needed for actions/checkout. steps: - uses: actions/checkout@v4 From 942d86d38cc541cd781824c9f0b056239c868c47 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:31:19 +0100 Subject: [PATCH 10/16] add back provenance to the deployments --- .github/workflows/release-please.yml | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 25649e1..caf9882 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -40,7 +40,9 @@ jobs: if: github.event_name == 'push' outputs: package-server-ai-released: ${{ steps.release.outputs['packages/sdk/server-ai--release_created'] }} + package-server-ai-tag-name: ${{ steps.release.outputs['packages/sdk/server-ai--tag_name'] }} package-server-ai-langchain-released: ${{ steps.release.outputs['packages/ai-providers/server-ai-langchain--release_created'] }} + package-server-ai-langchain-tag-name: ${{ steps.release.outputs['packages/ai-providers/server-ai-langchain--tag_name'] }} steps: - uses: googleapis/release-please-action@v4 id: release @@ -51,6 +53,8 @@ jobs: permissions: id-token: write # Needed for OIDC to get release secrets from AWS. if: ${{ needs.release-please.outputs.package-server-ai-released == 'true' }} + outputs: + package-hashes: ${{ steps.build.outputs.package-hashes }} steps: - uses: actions/checkout@v4 with: @@ -90,6 +94,8 @@ jobs: permissions: id-token: write # Needed for OIDC to get release secrets from AWS. if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} + outputs: + package-hashes: ${{ steps.build.outputs.package-hashes }} steps: - uses: actions/checkout@v4 with: @@ -161,3 +167,29 @@ jobs: with: password: ${{ env.PYPI_AUTH_TOKEN }} packages-dir: ${{ inputs.workspace_path }}/dist/ + + release-server-ai-provenance: + needs: ['release-please', 'release-server-ai'] + if: ${{ needs.release-please.outputs.package-server-ai-released == 'true' }} + permissions: + actions: read # Needed for detecting the GitHub Actions environment. + id-token: write # Needed for provenance signing. + contents: write # Needed for uploading assets to the release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.release-server-ai.outputs.package-hashes }}" + upload-assets: true + upload-tag-name: ${{ needs.release-please.outputs.package-server-ai-tag-name }} + + release-server-ai-langchain-provenance: + needs: ['release-please', 'release-server-ai-langchain'] + if: ${{ needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} + permissions: + actions: read # Needed for detecting the GitHub Actions environment. + id-token: write # Needed for provenance signing. + contents: write # Needed for uploading assets to the release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.release-server-ai-langchain.outputs.package-hashes }}" + upload-assets: true + upload-tag-name: ${{ needs.release-please.outputs.package-server-ai-langchain-tag-name }} From 2de3fd758dcf962e8a13032038b384e4076a1da1 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:33:39 +0100 Subject: [PATCH 11/16] Update release-please configuration to include component in tag for all packages --- release-please-config.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index 4b8a2d2..7da8563 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,4 +1,5 @@ { + "include-component-in-tag": true, "packages": { "packages/sdk/server-ai": { "release-type": "python", @@ -6,7 +7,6 @@ "bump-minor-pre-major": true, "include-v-in-tag": false, "extra-files": ["src/ldai/__init__.py", "../../../PROVENANCE.md"], - "include-component-in-tag": true, "component": "server-ai" }, "packages/ai-providers/server-ai-langchain": { @@ -15,7 +15,6 @@ "bump-minor-pre-major": true, "include-v-in-tag": false, "extra-files": ["src/ldai_langchain/__init__.py"], - "include-component-in-tag": true, "component": "server-ai-langchain" } } From 8084ea79561e6a91a4a7f4ab2f2e02aa76b8a46f Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:34:21 +0100 Subject: [PATCH 12/16] change component name --- release-please-config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index 7da8563..9c556a9 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -7,7 +7,7 @@ "bump-minor-pre-major": true, "include-v-in-tag": false, "extra-files": ["src/ldai/__init__.py", "../../../PROVENANCE.md"], - "component": "server-ai" + "component": "launchdarkly-server-sdk-ai" }, "packages/ai-providers/server-ai-langchain": { "release-type": "python", @@ -15,7 +15,7 @@ "bump-minor-pre-major": true, "include-v-in-tag": false, "extra-files": ["src/ldai_langchain/__init__.py"], - "component": "server-ai-langchain" + "component": "launchdarkly-server-sdk-ai-langchain" } } } From 55392acb4a4a45681502fa5ef33cbb2caae2bbdb Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo Date: Thu, 18 Dec 2025 09:40:34 +0100 Subject: [PATCH 13/16] Remove workspace_path input from build-docs action and update working directory to use default path. --- .github/actions/build-docs/action.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml index 3c5efc3..6f2c31a 100644 --- a/.github/actions/build-docs/action.yml +++ b/.github/actions/build-docs/action.yml @@ -1,15 +1,9 @@ name: Build Documentation description: 'Build Documentation for a package' -inputs: - workspace_path: - description: 'Path to the package to build docs for.' - required: false - default: 'packages/sdk/server-ai' runs: using: composite steps: - name: Build Documentation shell: bash - working-directory: ${{ inputs.workspace_path }} run: make docs From 0c2bb2009c3f4a6f2e493216e866eb40938b5ee1 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo <44273770+edwinokonkwo@users.noreply.github.com> Date: Thu, 18 Dec 2025 09:43:47 +0100 Subject: [PATCH 14/16] Update .github/workflows/release-please.yml Co-authored-by: semgrep-code-launchdarkly[bot] <167133144+semgrep-code-launchdarkly[bot]@users.noreply.github.com> --- .github/workflows/release-please.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index caf9882..0c0a44b 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -163,7 +163,8 @@ jobs: - name: Publish to PyPI if: ${{ inputs.dry_run != true }} - uses: pypa/gh-action-pypi-publish@release/v1 + # https://github.com/pypa/gh-action-pypi-publish/releases/tag/v1.8.13 - pinned to commit on 2024-04-13 + uses: pypa/gh-action-pypi-publish@3cc2c35166dfc1e5ea3bb0491ffdeedcaa50d7c with: password: ${{ env.PYPI_AUTH_TOKEN }} packages-dir: ${{ inputs.workspace_path }}/dist/ From 4077e41ea8519b364044c1c15fe7e82b1cdaedbf Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo <44273770+edwinokonkwo@users.noreply.github.com> Date: Thu, 18 Dec 2025 09:43:57 +0100 Subject: [PATCH 15/16] Update .github/workflows/release-please.yml Co-authored-by: semgrep-code-launchdarkly[bot] <167133144+semgrep-code-launchdarkly[bot]@users.noreply.github.com> --- .github/workflows/release-please.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 0c0a44b..c57ce78 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -124,7 +124,11 @@ jobs: ssm_parameter_pairs: '/production/common/releasing/pypi/token = PYPI_AUTH_TOKEN' - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + # Pin the action to a full 40-character commit SHA for security. + # Release v1 commit SHA as of 2024-06-14: + # https://github.com/pypa/gh-action-pypi-publish/releases/tag/v1.8.13 + # Commit SHA: 19af04270e8d898ea07a523bb392fa7fe98df87c + uses: pypa/gh-action-pypi-publish@19af04270e8d898ea07a523bb392fa7fe98df87c with: password: ${{ env.PYPI_AUTH_TOKEN }} packages-dir: packages/ai-providers/server-ai-langchain/dist/ From 7860c15f28dd3996cffc16a23db180f5eea1cdc9 Mon Sep 17 00:00:00 2001 From: Edwin Okonkwo <44273770+edwinokonkwo@users.noreply.github.com> Date: Thu, 18 Dec 2025 17:07:55 +0100 Subject: [PATCH 16/16] Update .github/workflows/release-please.yml Co-authored-by: Jason Bailey --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index c57ce78..751cdfc 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -93,7 +93,7 @@ jobs: needs: ['release-please'] permissions: id-token: write # Needed for OIDC to get release secrets from AWS. - if: ${{ always() && !failure() && !cancelled() && needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} + if: ${{ needs.release-please.outputs.package-server-ai-langchain-released == 'true' }} outputs: package-hashes: ${{ steps.build.outputs.package-hashes }} steps: