Skip to content

[sdk_v2] implements python sdk_v2#481

Open
prathikr wants to merge 14 commits intomainfrom
prathikrao/python-sdk-v2
Open

[sdk_v2] implements python sdk_v2#481
prathikr wants to merge 14 commits intomainfrom
prathikrao/python-sdk-v2

Conversation

@prathikr
Copy link
Contributor

@prathikr prathikr commented Mar 3, 2026

mvp

@vercel
Copy link

vercel bot commented Mar 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
foundry-local Ready Ready Preview, Comment Mar 5, 2026 6:32pm

Request Review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an MVP Python implementation of the Foundry Local SDK v2, including ctypes-based core interop, model/catalog abstractions, OpenAI-compatible clients, integration tests, packaging metadata, and CI build workflows.

Changes:

  • Introduces the Python SDK package (foundry_local_sdk) with core interop, catalog/model APIs, and chat/audio clients.
  • Adds a pytest-based integration test suite that mirrors the JS/C# SDK tests.
  • Adds Python build steps to GitHub Actions and wires them into the existing SDK build workflow.

Reviewed changes

Copilot reviewed 36 out of 39 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
sdk_v2/python/test/test_model.py Model cache + load/unload integration tests
sdk_v2/python/test/test_foundry_local_manager.py Manager initialization/catalog exposure tests
sdk_v2/python/test/test_catalog.py Catalog list/lookup/cached/variant tests
sdk_v2/python/test/openai/test_chat_client.py Chat completion + streaming tests + input validation cases
sdk_v2/python/test/openai/test_audio_client.py Audio transcription + streaming tests + validation cases
sdk_v2/python/test/openai/init.py Test package marker for openai/ tests
sdk_v2/python/test/detail/test_model_load_manager.py ModelLoadManager interop + external-service tests
sdk_v2/python/test/detail/init.py Test package marker for detail/ tests
sdk_v2/python/test/conftest.py Session fixtures/config shared across tests
sdk_v2/python/test/init.py Test package marker
sdk_v2/python/test/README.md Test-suite documentation and conventions
sdk_v2/python/src/version.py Package version source
sdk_v2/python/src/openai/chat_client.py OpenAI-compatible chat client implementation
sdk_v2/python/src/openai/audio_client.py OpenAI-compatible audio transcription client implementation
sdk_v2/python/src/openai/init.py Exports for OpenAI-compatible clients
sdk_v2/python/src/model_variant.py Model variant operations + client creation
sdk_v2/python/src/model.py Alias-level model wrapper over variants
sdk_v2/python/src/logging_helper.py SDK log-level mapping helper
sdk_v2/python/src/imodel.py Shared model interface (Model/ModelVariant)
sdk_v2/python/src/foundry_local_manager.py Singleton manager + web-service lifecycle
sdk_v2/python/src/exception.py SDK exception type
sdk_v2/python/src/detail/utils.py Shared internal helpers (cached model IDs, StrEnum)
sdk_v2/python/src/detail/native_downloader.py NuGet-based native binary downloader + CLI
sdk_v2/python/src/detail/model_load_manager.py Load/unload abstraction (interop vs web service)
sdk_v2/python/src/detail/model_data_types.py Pydantic models for catalog/model metadata
sdk_v2/python/src/detail/core_interop.py ctypes FFI layer for Foundry Local Core
sdk_v2/python/src/detail/init.py Internal module exports
sdk_v2/python/src/configuration.py SDK configuration model + validation
sdk_v2/python/src/catalog.py Catalog implementation (listing/lookup/cached/loaded)
sdk_v2/python/src/init.py Top-level package exports + logger setup
sdk_v2/python/requirements.txt Runtime dependencies
sdk_v2/python/requirements-dev.txt Dev/test dependencies
sdk_v2/python/pyproject.toml Packaging + pytest configuration
sdk_v2/python/examples/chat_completion.py Example usage script
sdk_v2/python/README.md Python SDK documentation
sdk_v2/python/LICENSE.txt License file
sdk_v2/python/.gitignore Python SDK ignore rules
.github/workflows/foundry-local-sdk-build.yml Adds Python build jobs to SDK build workflow
.github/workflows/build-python-steps.yml New reusable workflow to build/test/package Python SDK

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@prathikr prathikr requested a review from Copilot March 5, 2026 22:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 36 out of 39 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +13
from dataclasses import dataclass, field
from typing import Callable, Optional

from ..detail.core_interop import CoreInterop, InteropRequest
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

AudioClient raises FoundryLocalException later in this file, but it is not imported here, which will cause a NameError at runtime on error paths. Import it (e.g., from ..exception import FoundryLocalException) and consider removing the unused field import from dataclasses.

Suggested change
from dataclasses import dataclass, field
from typing import Callable, Optional
from ..detail.core_interop import CoreInterop, InteropRequest
from dataclasses import dataclass
from typing import Callable, Optional
from ..detail.core_interop import CoreInterop, InteropRequest
from ..exception import FoundryLocalException

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +90
logger.info("Download response: %s", response)
if response.error is not None:
raise FoundryLocalException(f"Failed to download model: {response.error}")
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

FoundryLocalException is referenced but not imported in this module, which will raise NameError when a download fails. Add the missing import (from .exception import FoundryLocalException) near the top of the file.

Copilot uses AI. Check for mistakes.
f"HTTP request failed when listing loaded models from {self._external_service_url}"
) from e
except json.JSONDecodeError as e:
raise FoundryLocalException(f"Failed to decode JSON response: Response was: {response.data}") from e
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

response here is a requests.Response, which does not have a .data attribute; this will throw an AttributeError and mask the real JSON parsing failure. Use response.text (or capture the text into a local variable and reference that) in the exception message.

Suggested change
raise FoundryLocalException(f"Failed to decode JSON response: Response was: {response.data}") from e
raise FoundryLocalException(f"Failed to decode JSON response: Response was: {content}") from e

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +43
"""
Load a model by its ID.
:param model_id: The ID of the model to load.
:raises NotImplementedError: If loading via external service is attempted.
"""
if self._external_service_url:
self._web_load_model(model_id)
return
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The docstring claims NotImplementedError is raised when loading via external service, but the method is implemented (_web_load_model). Update the docstring to describe the actual behavior and raised exception types.

Copilot uses AI. Check for mistakes.
dynamic = ["version", "dependencies"]
description = "Foundry Local Manager Python SDK: Control-plane SDK for Foundry Local."
readme = "README.md"
requires-python = ">=3.10"
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

requires-python is >=3.10 but the classifiers include Python 3.9, which is inconsistent for packaging metadata. Remove the 3.9 classifier or lower requires-python (and ensure the codebase avoids 3.10-only syntax if doing so).

Copilot uses AI. Check for mistakes.
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

requires-python is >=3.10 but the classifiers include Python 3.9, which is inconsistent for packaging metadata. Remove the 3.9 classifier or lower requires-python (and ensure the codebase avoids 3.10-only syntax if doing so).

Suggested change
"Programming Language :: Python :: 3.9",

Copilot uses AI. Check for mistakes.

## Prerequisites

1. **Python 3.9+** (tested with 3.12/3.13)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

This claims Python 3.9+, but pyproject.toml sets requires-python = \">=3.10\". Update this doc to match the supported minimum version.

Suggested change
1. **Python 3.9+** (tested with 3.12/3.13)
1. **Python 3.10+** (tested with 3.12/3.13)

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +17
from openai.types.chat.chat_completion_message_param import *
from openai.types.chat.completion_create_params import CompletionCreateParamsBase, \
CompletionCreateParamsNonStreaming, \
CompletionCreateParamsStreaming
from openai.types.shared_params import Metadata
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

Avoid import * here since it obscures what types are used and can pollute the module namespace; import only ChatCompletionMessageParam (and any other required symbols) explicitly. Also, Metadata is imported but not used in this file—removing it reduces confusion and avoids lint failures.

Suggested change
from openai.types.chat.chat_completion_message_param import *
from openai.types.chat.completion_create_params import CompletionCreateParamsBase, \
CompletionCreateParamsNonStreaming, \
CompletionCreateParamsStreaming
from openai.types.shared_params import Metadata
from openai.types.chat.chat_completion_message_param import ChatCompletionMessageParam
from openai.types.chat.completion_create_params import CompletionCreateParamsBase, \
CompletionCreateParamsNonStreaming, \
CompletionCreateParamsStreaming

Copilot uses AI. Check for mistakes.
pass

@abstractmethod
def load(self,) -> None:
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

The trailing comma in the method signature is unnecessary and inconsistent with the other method definitions. Consider changing it to def load(self) -> None: for readability and style consistency.

Suggested change
def load(self,) -> None:
def load(self) -> None:

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants