Skip to content
This repository was archived by the owner on Jun 7, 2026. It is now read-only.

feat: Python SDK for Koine gateway - #42

Merged
matthew-petty merged 17 commits into
mainfrom
feat/2-python-sdk
Dec 25, 2025
Merged

feat: Python SDK for Koine gateway#42
matthew-petty merged 17 commits into
mainfrom
feat/2-python-sdk

Conversation

@matthew-petty

Copy link
Copy Markdown
Member

Summary

Implements a complete Python SDK for Koine gateway, closing #2.

  • Full API parity with TypeScript SDKgenerate_text, generate_object, stream_text
  • Type-safe — Pydantic models, full type hints, pyright strict mode
  • Well-tested — 20 tests with coverage reporting
  • CI integrated — Linting (ruff), type checking (pyright), and tests run on every PR

Features

Text Generation

from koine_sdk import KoineConfig, generate_text

config = KoineConfig(
    base_url="http://localhost:3100",
    auth_key="your-api-key",
    timeout=300.0,
)

result = await generate_text(config, prompt="Hello!")
print(result.text)

Streaming (with async context manager for resource safety)

from koine_sdk import stream_text

async with stream_text(config, prompt="Write a story") as result:
    async for chunk in result.text_stream:
        print(chunk, end="")
    
    usage = await result.usage()

Structured Output

from pydantic import BaseModel
from koine_sdk import generate_object

class Person(BaseModel):
    name: str
    age: int

result = await generate_object(config, prompt="Extract: John is 30", schema=Person)
print(result.object.name)  # "John"

Changes

New Files

  • packages/sdks/python/ — Complete Python SDK package
    • src/koine_sdk/ — Client, types, errors modules
    • tests/ — Comprehensive test suite
    • pyproject.toml — Package configuration with ruff, pyright, pytest

Documentation Updates

  • docs/sdk-guide.md — Added Python examples alongside TypeScript
  • docs/README.md — Added Python SDK quick start
  • docs/examples/python/ — Runnable examples (hello, stream, conversation, extract_recipe)
  • packages/sdks/python/README.md — SDK documentation
  • CONTRIBUTING.md — Marked Python SDK as complete in roadmap
  • README.md — Added Python SDK to packages table

CI Updates

  • .github/workflows/ci.yml — Added Python linting and testing with uv caching

Test plan

  • All 20 Python SDK tests pass locally
  • TypeScript tests still pass
  • Linting passes (ruff check, ruff format, pyright)
  • Examples work against running gateway
  • CI passes on this PR

Related Issues

Closes #2 (partial)

- Create packages/sdks/python/ with hatch build system
- Add pyproject.toml with pinned dependencies (httpx, pydantic)
- Add dev dependencies (pytest, pytest-asyncio, pytest-httpx, pyright, ruff)
- Configure pyright for strict type checking
- Add py.typed marker for PEP 561 compliance
- Add README.md with usage examples
- Add __init__.py with public API exports (placeholder imports)
- Add KoineError exception class with error codes
- Add KoineConfig dataclass for gateway configuration
- Add KoineUsage, GenerateTextResult, GenerateObjectResult models
- Add StreamTextResult dataclass for streaming results
- Add internal response types for gateway parsing
- Add client.py stub with function signatures
- Update .gitignore with Python patterns
- Add uv.lock for reproducible dependencies
- Add generate_text() for plain text generation
- Add generate_object() with Pydantic schema validation
- Use httpx.AsyncClient for async HTTP requests
- Convert Pydantic models to JSON Schema for gateway
- Add proper error handling with KoineError
- Rename internal types to Gateway* prefix (not underscore private)
- Add SSE parser async generator for parsing event streams
- Add stream processor that resolves futures as events arrive
- Implement stream_text() with AsyncIterator for text chunks
- Use asyncio.Future for session_id (early), usage (late), text (late)
- Update StreamTextResult to use proper async futures
- Handle critical vs non-critical event parse errors
- Properly close httpx client and response on stream completion
19 focused tests covering:
- KoineError construction and properties
- generate_text: success, system prompts, HTTP errors, invalid responses
- generate_object: schema conversion, validation, session continuity
- stream_text: SSE parsing, early session resolution, error handling
- hello.py: Basic generate_text usage
- extract_recipe.py: Structured output with Pydantic schemas
- stream.py: Real-time streaming with stream_text
- conversation.py: Multi-turn conversations with session_id
- Omit None values from request body (gateway rejects null)
- Add camelCase aliases to KoineUsage for gateway response parsing
- Update test mocks to use camelCase field names
Consume usage and text futures after stream error to prevent
"Future exception was never retrieved" warning.
- Add python-dotenv==1.2.1 to dev dependencies
- Update all Python examples to use load_dotenv(find_dotenv())
- Examples now auto-find .env from parent directories
- Update root README with Python SDK in intro and packages table
- Update docs/README with Python SDK quick start example
- Update docs/sdk-guide.md with Python examples for all sections
- Update docs/examples/README.md with correct Python run instructions
- Restructure packages/sdks/python/README.md to match TypeScript pattern
- Update CONTRIBUTING.md to mark Python SDK as completed
- Replace broad `except Exception` with specific exception types
- Remove undocumented NO_RESPONSE_BODY error code from docstring
- Catch ValidationError alongside JSONDecodeError in SSE processing
- Remove dead TYPE_CHECKING import and empty block
- Simplify session_id tracking using future.done() instead of variable
- Add test_with_session_id for generate_text
Rename future attributes with underscore prefix to guide users toward
the convenience methods (session_id(), usage(), text()) instead of
direct future access.
Fixes resource leak by requiring stream_text to be used with async with:

    async with stream_text(config, prompt="Hello") as result:
        async for chunk in result.text_stream:
            print(chunk)

This ensures HTTP client and response are always cleaned up, even if
the stream is not fully consumed or an exception occurs.

BREAKING CHANGE: stream_text now returns a context manager instead of
a coroutine. Must use `async with stream_text(...)` instead of
`await stream_text(...)`.
- Setup Python 3.13 and uv
- Run ruff linting and pyright type checking
- Run pytest with coverage reporting
- Add Python coverage to Codecov upload
@codecov

codecov Bot commented Dec 25, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.53448% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/sdks/python/src/koine_sdk/client.py 90.13% 15 Missing ⚠️

📢 Thoughts on this report? Let us know!

@matthew-petty
matthew-petty merged commit 65ef9b7 into main Dec 25, 2025
3 checks passed
@matthew-petty
matthew-petty deleted the feat/2-python-sdk branch December 25, 2025 19:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create Python SDK

1 participant