From c4c5d1f040dfbdc32fc7849694824d7cfeeaf075 Mon Sep 17 00:00:00 2001 From: Ankit Kumar Date: Tue, 29 Jul 2025 05:01:15 +0530 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=93=A6=20NEW:=C2=A0Python=20Release?= =?UTF-8?q?=20System?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .releaserc.json | 64 ++++++++++++++++++++++++++++++++ CHANGELOG.md | 21 +++++++++++ langbase/__init__.py | 3 ++ pyproject.toml | 29 ++++++++++++++- release.py | 88 ++++++++++++++++++++++++++++++++++++++++++++ requirements-dev.txt | 3 ++ 6 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 .releaserc.json create mode 100644 CHANGELOG.md create mode 100644 release.py diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..2bc3a7f --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,64 @@ +{ + "branches": ["main"], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "releaseRules": [ + {"type": "๐Ÿ“ฆ NEW", "release": "major"}, + {"type": "๐Ÿ‘Œ IMPROVE", "release": "patch"}, + {"type": "๐Ÿ› FIX", "release": "patch"}, + {"type": "๐Ÿš€ RELEASE", "release": "patch"}, + {"type": "๐Ÿ“– DOC", "release": false}, + {"type": "๐Ÿค– TEST", "release": false}, + {"type": "โ€ผ๏ธ BREAKING", "release": "major"} + ], + "parserOpts": { + "pattern": "^(๐Ÿ“ฆ NEW|๐Ÿ‘Œ IMPROVE|๐Ÿ› FIX|๐Ÿš€ RELEASE|๐Ÿ“– DOC|๐Ÿค– TEST|โ€ผ๏ธ BREAKING): (.*)$", + "groupCorrespondence": ["type", "subject"] + } + } + ], + [ + "@semantic-release/release-notes-generator", + { + "parserOpts": { + "pattern": "^(๐Ÿ“ฆ NEW|๐Ÿ‘Œ IMPROVE|๐Ÿ› FIX|๐Ÿš€ RELEASE|๐Ÿ“– DOC|๐Ÿค– TEST|โ€ผ๏ธ BREAKING): (.*)$", + "groupCorrespondence": ["type", "subject"] + }, + "writerOpts": { + "transform": { + "hash": false, + "committerDate": false, + "authorDate": false, + "authorName": false, + "authorEmail": false, + "committerName": false, + "committerEmail": false + }, + "groupBy": "type", + "commitGroupsSort": ["๐Ÿ“ฆ NEW", "๐Ÿ‘Œ IMPROVE", "๐Ÿ› FIX", "โ€ผ๏ธ BREAKING", "๐Ÿ“– DOC", "๐Ÿค– TEST"], + "commitsSort": ["subject"], + "noteGroupsSort": "title" + } + } + ], + [ + "@semantic-release/changelog", + { + "changelogFile": "CHANGELOG.md" + } + ], + [ + "@semantic-release/git", + { + "assets": [ + "CHANGELOG.md", + "pyproject.toml", + "langbase/__init__.py" + ], + "message": "๐Ÿš€ RELEASE: ${nextRelease.version}\n\n${nextRelease.notes}" + } + ] + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..80c0bf9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- Initial Python SDK for Langbase API +- Support for Pipes, Memories, Threads, Tools, and Workflows +- Comprehensive type definitions and error handling +- Streaming support for real-time responses +- Memory and RAG functionality +- Agent and workflow orchestration + +## [0.1.0] - 2024-01-01 + +### Added +- Initial release of the Langbase Python SDK diff --git a/langbase/__init__.py b/langbase/__init__.py index 2521030..1ddc53f 100644 --- a/langbase/__init__.py +++ b/langbase/__init__.py @@ -64,6 +64,9 @@ from .workflow import TimeoutError, Workflow __version__ = "0.1.0" +__author__ = "LangbaseInc" +__description__ = "Python SDK for the Langbase API" + __all__ = [ # Errors "APIConnectionError", diff --git a/pyproject.toml b/pyproject.toml index 9dc0a65..7f93d7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "langbase" version = "0.1.0" description = "Python SDK for the Langbase API" readme = "README.md" -license = {text = "MIT"} +license = {text = "Apache-2.0"} authors = [ { name = "Saqib", email = "saqib@langbase.com" }, { name = "Ankit", email = "ankit@langbase.com" }, @@ -13,13 +13,17 @@ keywords = ["ai", "langbase", "agent", "memory", "rag", "mcp", "pipes", "workflo classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules", ] dependencies = [ @@ -27,6 +31,11 @@ dependencies = [ "typing-extensions>=4.0.0", ] +[project.optional-dependencies] +release = [ + "python-semantic-release>=8.0.0", +] + [project.urls] Documentation = "https://docs.langbase.com" Homepage = "https://langbase.com" @@ -102,3 +111,19 @@ precision = 2 [tool.coverage.html] directory = "htmlcov" + +[tool.semantic_release] +version_toml = ["pyproject.toml:project.version"] +version_variables = [ + "langbase/__init__.py:__version__", +] +branch = "main" +upload_to_PyPI = false +upload_to_release = false +build_command = "pip install build && python -m build" + +[tool.semantic_release.commit_parser_options] +allowed_tags = ["๐Ÿ“ฆ NEW", "๐Ÿ‘Œ IMPROVE", "๐Ÿ› FIX", "๐Ÿš€ RELEASE", "๐Ÿ“– DOC", "๐Ÿค– TEST", "โ€ผ๏ธ BREAKING"] +minor_tags = ["๐Ÿ“ฆ NEW"] +patch_tags = ["๐Ÿ‘Œ IMPROVE", "๐Ÿ› FIX", "๐Ÿš€ RELEASE"] +major_tags = ["โ€ผ๏ธ BREAKING"] diff --git a/release.py b/release.py new file mode 100644 index 0000000..04a1b22 --- /dev/null +++ b/release.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +""" +Simple release script for Langbase Python SDK. +Usage: python release.py +""" + +import os +import subprocess +import sys + +# Fix Windows encoding issues with emojis +os.environ["PYTHONUTF8"] = "1" +os.environ["PYTHONIOENCODING"] = "utf-8" + + +def run_command(cmd, description): + """Run a command and handle errors.""" + print(f"๐Ÿ”„ {description}...") + print(f" Running: {cmd}") + try: + result = subprocess.run( + cmd, + shell=True, + check=True, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + # Show both stdout and stderr + if result.stdout.strip(): + print("๐Ÿ“ค Output:") + print(result.stdout) + if result.stderr.strip(): + print("โš ๏ธ Warnings:") + print(result.stderr) + if not result.stdout.strip() and not result.stderr.strip(): + print("โœ… Command completed (no output)") + return True + except subprocess.CalledProcessError as e: + print(f"โŒ Error: {e}") + print(f"โŒ Command that failed: {cmd}") + if e.stdout: + print(f"๐Ÿ“ค Output: {e.stdout}") + if e.stderr: + print(f"๐Ÿ“ค Error details: {e.stderr}") + return False + + +def main(): + """Run the complete release process.""" + print("๐Ÿš€ Starting Langbase SDK release process...\n") + + # Step 1: Confirm release + try: + confirm = input("\nโ“ Proceed with release? (y/N): ").lower().strip() + if confirm != "y" and confirm != "yes": + print("โŒ Release cancelled") + return + except KeyboardInterrupt: + print("\nโŒ Release cancelled") + return + + # Step 2: Create version + print("\n๐Ÿ“ฆ Creating new version...") + if not run_command("semantic-release version", "Creating version"): + print("โŒ Failed to create version") + sys.exit(1) + + # Step 3: Configure git to push tags automatically (one-time setup) + run_command( + "git config push.followTags true", "Configuring git to push tags automatically" + ) + + # Step 4: Push everything to origin + print("\nโฌ†๏ธ Pushing to origin...") + if not run_command("git push origin main", "Pushing commits and tags"): + print("โŒ Failed to push to origin") + sys.exit(1) + + print("\nโœ… Release completed successfully!") + print("๐ŸŽฏ Next steps (optional):") + print(" โ€ข python -m build # Build packages") + print(" โ€ข twine upload dist/* # Upload to PyPI") + + +if __name__ == "__main__": + main() diff --git a/requirements-dev.txt b/requirements-dev.txt index 24b64b2..d2ea117 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -21,3 +21,6 @@ twine>=4.0.0 # Development utilities ipdb>=0.13.0 python-dotenv>=0.19.0 + +# release +python-semantic-release>=8.0.0 From 6a3989730d3cfef4a6cdb29d54d567620b7a2bf4 Mon Sep 17 00:00:00 2001 From: Ankit Kumar Date: Tue, 29 Jul 2025 05:23:01 +0530 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=91=8C=20IMPROVE:=20Contribution.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c32ecc4..94f9650 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,6 +83,17 @@ pytest -v pre-commit run --all-files ``` +### 6. Release a new version +```bash +python release.py +``` + +# 3. Optional: Publish to PyPI +``` +python -m build +twine upload dist/* +``` + ## Quick Checklist Before pushing your changes, ensure: From 5a7bef72a728e9805fa40c589cd0aceb90ddbcd3 Mon Sep 17 00:00:00 2001 From: Ankit Kumar <98694380+arre-ankit@users.noreply.github.com> Date: Wed, 30 Jul 2025 00:45:36 +0530 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=90=9B=20FIX:=C2=A0Update=20.releaser?= =?UTF-8?q?c.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .releaserc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.releaserc.json b/.releaserc.json index 2bc3a7f..8d25f53 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -5,7 +5,7 @@ "@semantic-release/commit-analyzer", { "releaseRules": [ - {"type": "๐Ÿ“ฆ NEW", "release": "major"}, + {"type": "๐Ÿ“ฆ NEW", "release": "minor"}, {"type": "๐Ÿ‘Œ IMPROVE", "release": "patch"}, {"type": "๐Ÿ› FIX", "release": "patch"}, {"type": "๐Ÿš€ RELEASE", "release": "patch"}, From 5fac4610720c4397c11254efda4ea32da8fce723 Mon Sep 17 00:00:00 2001 From: Ankit Kumar <98694380+arre-ankit@users.noreply.github.com> Date: Wed, 30 Jul 2025 00:46:01 +0530 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=90=9B=20FIX:=C2=A0Update=20CONTRIBUT?= =?UTF-8?q?ING.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94f9650..d598c3e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,7 +88,7 @@ pre-commit run --all-files python release.py ``` -# 3. Optional: Publish to PyPI +### 3. Optional: Publish to PyPI ``` python -m build twine upload dist/* From d16544be5caaf7a35eb61598b1e5ffa5abff10c3 Mon Sep 17 00:00:00 2001 From: Saqib Ameen Date: Wed, 6 Aug 2025 18:01:55 -0600 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=91=8C=20IMPROVE:=20release=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .releaserc.json | 64 ----- CHANGELOG.md | 20 -- README.md | 30 ++- examples/agent/agent.run.py | 4 +- examples/agent/agent.run.stream.py | 2 +- examples/agent/agent.run.workflow.py | 2 +- examples/workflow/email_processing.py | 4 +- examples/workflow/summarization.py | 4 +- langbase/__init__.py | 2 +- pyproject.toml | 9 +- release.py | 327 +++++++++++++++++++++++--- requirements-dev.txt | 1 + 12 files changed, 327 insertions(+), 142 deletions(-) delete mode 100644 .releaserc.json diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 8d25f53..0000000 --- a/.releaserc.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "branches": ["main"], - "plugins": [ - [ - "@semantic-release/commit-analyzer", - { - "releaseRules": [ - {"type": "๐Ÿ“ฆ NEW", "release": "minor"}, - {"type": "๐Ÿ‘Œ IMPROVE", "release": "patch"}, - {"type": "๐Ÿ› FIX", "release": "patch"}, - {"type": "๐Ÿš€ RELEASE", "release": "patch"}, - {"type": "๐Ÿ“– DOC", "release": false}, - {"type": "๐Ÿค– TEST", "release": false}, - {"type": "โ€ผ๏ธ BREAKING", "release": "major"} - ], - "parserOpts": { - "pattern": "^(๐Ÿ“ฆ NEW|๐Ÿ‘Œ IMPROVE|๐Ÿ› FIX|๐Ÿš€ RELEASE|๐Ÿ“– DOC|๐Ÿค– TEST|โ€ผ๏ธ BREAKING): (.*)$", - "groupCorrespondence": ["type", "subject"] - } - } - ], - [ - "@semantic-release/release-notes-generator", - { - "parserOpts": { - "pattern": "^(๐Ÿ“ฆ NEW|๐Ÿ‘Œ IMPROVE|๐Ÿ› FIX|๐Ÿš€ RELEASE|๐Ÿ“– DOC|๐Ÿค– TEST|โ€ผ๏ธ BREAKING): (.*)$", - "groupCorrespondence": ["type", "subject"] - }, - "writerOpts": { - "transform": { - "hash": false, - "committerDate": false, - "authorDate": false, - "authorName": false, - "authorEmail": false, - "committerName": false, - "committerEmail": false - }, - "groupBy": "type", - "commitGroupsSort": ["๐Ÿ“ฆ NEW", "๐Ÿ‘Œ IMPROVE", "๐Ÿ› FIX", "โ€ผ๏ธ BREAKING", "๐Ÿ“– DOC", "๐Ÿค– TEST"], - "commitsSort": ["subject"], - "noteGroupsSort": "title" - } - } - ], - [ - "@semantic-release/changelog", - { - "changelogFile": "CHANGELOG.md" - } - ], - [ - "@semantic-release/git", - { - "assets": [ - "CHANGELOG.md", - "pyproject.toml", - "langbase/__init__.py" - ], - "message": "๐Ÿš€ RELEASE: ${nextRelease.version}\n\n${nextRelease.notes}" - } - ] - ] -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c0bf9..825c32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1 @@ # Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -### Added -- Initial Python SDK for Langbase API -- Support for Pipes, Memories, Threads, Tools, and Workflows -- Comprehensive type definitions and error handling -- Streaming support for real-time responses -- Memory and RAG functionality -- Agent and workflow orchestration - -## [0.1.0] - 2024-01-01 - -### Added -- Initial release of the Langbase Python SDK diff --git a/README.md b/README.md index e5101fd..6e61cc5 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,18 @@ The following examples are for reference only. Prefer docs for the latest inform ## Installation +Install Langbase SDK: + ```bash pip install langbase ``` +Install dotenv: + +```bash +pip install dotenv +``` + ## Quick Start ### 1. Set up your API key @@ -54,6 +62,7 @@ llm_api_key = os.getenv("LLM_API_KEY") # Initialize the client langbase = Langbase(api_key=langbase_api_key) +langbase = Langbase(api_key=langbase_api_key) ``` ### 3. Generate text @@ -188,6 +197,7 @@ results = langbase.memories.retrieve( ```python # Run an agent with tools +response = langbase.agent.run( response = langbase.agent.run( model="openai:gpt-4", messages=[{"role": "user", "content": "Search for AI news"}], @@ -202,6 +212,7 @@ response = langbase.agent.run( ```python # Chunk text for processing +chunks = langbase.chunker( chunks = langbase.chunker( content="Long text to split...", chunk_max_length=1024, @@ -209,12 +220,14 @@ chunks = langbase.chunker( ) # Generate embeddings +embeddings = langbase.embed( embeddings = langbase.embed( chunks=["Text 1", "Text 2"], embedding_model="openai:text-embedding-3-small", ) # Parse documents +content = langbase.parser( content = langbase.parser( document=open("document.pdf", "rb"), document_name="document.pdf", @@ -224,13 +237,14 @@ content = langbase.parser( ## Examples -Explore the [examples](./examples) directory for complete working examples: +Explore the [examples](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/examples) directory for complete working examples: -- [Agent with tools](./examples/agent/) -- [Work with memory](./examples/memory/) -- [Generate text](./examples/pipes/pipes.run.py) -- [Document processing](./examples/parser/) -- [Workflow automation](./examples/workflow/) +- [Generate text](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/examples/agent/agent.run.py) +- [Stream text](https://github.com/LangbaseInc/langbase-python-sdk/blob/main/examples/agent/agent.run.stream.py) +- [Work with memory](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/examples/memory/) +- [Agent with tools](https://github.com/LangbaseInc/langbase-python-sdk/blob/main/examples/agent/agent.run.tool.py) +- [Document processing](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/examples/parser/) +- [Workflow automation](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/examples/workflow/) ## SDK Reference @@ -238,7 +252,7 @@ For detailed SDK documentation, visit [langbase.com/docs/sdk](https://langbase.c ## Contributing -We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. +We welcome contributions! Please see our [Contributing Guide](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/CONTRIBUTING.md) for details. ## Support @@ -248,4 +262,4 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f ## License -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. +See the [LICENSE](https://github.com/LangbaseInc/langbase-python-sdk/tree/main/LICENSE) file for details. diff --git a/examples/agent/agent.run.py b/examples/agent/agent.run.py index 53514d0..691ee8f 100644 --- a/examples/agent/agent.run.py +++ b/examples/agent/agent.run.py @@ -20,12 +20,12 @@ def main(): if not langbase_api_key: print("โŒ Missing LANGBASE_API_KEY in environment variables.") - print("Please set: export LANGBASE_API_KEY='your_langbase_api_key'") + print("Please set: LANGBASE_API_KEY='your_langbase_api_key' in .env file") exit(1) if not llm_api_key: print("โŒ Missing LLM_API_KEY in environment variables.") - print("Please set: export LLM_API_KEY='your_llm_api_key'") + print("Please set: LLM_API_KEY='your_llm_api_key' in .env file") exit(1) # Initialize Langbase client diff --git a/examples/agent/agent.run.stream.py b/examples/agent/agent.run.stream.py index 1a82d41..1c83427 100644 --- a/examples/agent/agent.run.stream.py +++ b/examples/agent/agent.run.stream.py @@ -20,7 +20,7 @@ def main(): if not langbase_api_key: print("โŒ Missing LANGBASE_API_KEY in environment variables.") - print("Please set: export LANGBASE_API_KEY='your_langbase_api_key'") + print("Please set: LANGBASE_API_KEY='your_langbase_api_key' in .env file") exit(1) # Initialize Langbase client diff --git a/examples/agent/agent.run.workflow.py b/examples/agent/agent.run.workflow.py index b939d12..45bcac9 100644 --- a/examples/agent/agent.run.workflow.py +++ b/examples/agent/agent.run.workflow.py @@ -31,7 +31,7 @@ async def main(): if not llm_api_key: print("โŒ Missing LLM_API_KEY in environment variables.") - print("Please set: export LLM_API_KEY='your_llm_api_key'") + print("Please set: LLM_API_KEY='your_llm_api_key' in .env file") exit(1) # Initialize Langbase client and Workflow diff --git a/examples/workflow/email_processing.py b/examples/workflow/email_processing.py index 12da295..e1e18f7 100644 --- a/examples/workflow/email_processing.py +++ b/examples/workflow/email_processing.py @@ -33,12 +33,12 @@ async def process_email(email_content: str): if not langbase_api_key: print("โŒ Missing LANGBASE_API_KEY in environment variables.") - print("Please set: export LANGBASE_API_KEY='your_langbase_api_key'") + print("Please set: LANGBASE_API_KEY='your_langbase_api_key' in .env file") exit(1) if not llm_api_key: print("โŒ Missing LLM_API_KEY in environment variables.") - print("Please set: export LLM_API_KEY='your_llm_api_key'") + print("Please set: LLM_API_KEY='your_llm_api_key' in .env file") exit(1) # Initialize Langbase diff --git a/examples/workflow/summarization.py b/examples/workflow/summarization.py index 61d7b66..707b76d 100644 --- a/examples/workflow/summarization.py +++ b/examples/workflow/summarization.py @@ -32,12 +32,12 @@ async def process_text(input_text: str): if not langbase_api_key: print("โŒ Missing LANGBASE_API_KEY in environment variables.") - print("Please set: export LANGBASE_API_KEY='your_langbase_api_key'") + print("Please set: LANGBASE_API_KEY='your_langbase_api_key' in .env file") exit(1) if not llm_api_key: print("โŒ Missing LLM_API_KEY in environment variables.") - print("Please set: export LLM_API_KEY='your_llm_api_key'") + print("Please set: LLM_API_KEY='your_llm_api_key' in .env file") exit(1) # Initialize Langbase diff --git a/langbase/__init__.py b/langbase/__init__.py index 1ddc53f..02989d6 100644 --- a/langbase/__init__.py +++ b/langbase/__init__.py @@ -63,7 +63,7 @@ ) from .workflow import TimeoutError, Workflow -__version__ = "0.1.0" +__version__ = "0.0.0" __author__ = "LangbaseInc" __description__ = "Python SDK for the Langbase API" diff --git a/pyproject.toml b/pyproject.toml index 7f93d7e..20c69ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,16 @@ [project] name = "langbase" -version = "0.1.0" +version = "0.0.0" description = "Python SDK for the Langbase API" readme = "README.md" license = {text = "Apache-2.0"} authors = [ - { name = "Saqib", email = "saqib@langbase.com" }, - { name = "Ankit", email = "ankit@langbase.com" }, + { name = "Saqib Ameen", email = "saqib@langbase.com" }, + { name = "Ankit Kumar", email = "ankit@langbase.com" }, ] requires-python = ">=3.7" -keywords = ["ai", "langbase", "agent", "memory", "rag", "mcp", "pipes", "workflow"] +keywords = ["ai", "langbase", "agent", "memory", "rag", "mcp", "pipes", "workflow", "llms"] classifiers = [ - "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", diff --git a/release.py b/release.py index 04a1b22..2c70817 100644 --- a/release.py +++ b/release.py @@ -1,19 +1,21 @@ #!/usr/bin/env python3 """ -Simple release script for Langbase Python SDK. +Interactive release script for Langbase Python SDK. Usage: python release.py """ import os +import re import subprocess import sys +from datetime import datetime # Fix Windows encoding issues with emojis os.environ["PYTHONUTF8"] = "1" os.environ["PYTHONIOENCODING"] = "utf-8" -def run_command(cmd, description): +def run_command(cmd, description, capture_output=True): """Run a command and handle errors.""" print(f"๐Ÿ”„ {description}...") print(f" Running: {cmd}") @@ -22,21 +24,22 @@ def run_command(cmd, description): cmd, shell=True, check=True, - capture_output=True, + capture_output=capture_output, text=True, encoding="utf-8", errors="replace", ) - # Show both stdout and stderr - if result.stdout.strip(): - print("๐Ÿ“ค Output:") - print(result.stdout) - if result.stderr.strip(): - print("โš ๏ธ Warnings:") - print(result.stderr) - if not result.stdout.strip() and not result.stderr.strip(): - print("โœ… Command completed (no output)") - return True + if capture_output: + # Show both stdout and stderr + if result.stdout.strip(): + print("๐Ÿ“ค Output:") + print(result.stdout) + if result.stderr.strip(): + print("โš ๏ธ Warnings:") + print(result.stderr) + if not result.stdout.strip() and not result.stderr.strip(): + print("โœ… Command completed (no output)") + return True, result.stdout if capture_output else "" except subprocess.CalledProcessError as e: print(f"โŒ Error: {e}") print(f"โŒ Command that failed: {cmd}") @@ -44,44 +47,296 @@ def run_command(cmd, description): print(f"๐Ÿ“ค Output: {e.stdout}") if e.stderr: print(f"๐Ÿ“ค Error details: {e.stderr}") + return False, "" + + +def get_current_version(): + """Get current version from pyproject.toml.""" + try: + with open("pyproject.toml", "r", encoding="utf-8") as f: + content = f.read() + match = re.search(r'version = "([^"]+)"', content) + if match: + return match.group(1) + except FileNotFoundError: + pass + return "0.0.0" + + +def parse_version(version): + """Parse version string into major, minor, patch.""" + parts = version.split(".") + if len(parts) != 3: + raise ValueError(f"Invalid version format: {version}") + return int(parts[0]), int(parts[1]), int(parts[2]) + + +def bump_version(current_version, bump_type): + """Bump version based on type.""" + major, minor, patch = parse_version(current_version) + + if bump_type == "major": + return f"{major + 1}.0.0" + elif bump_type == "minor": + return f"{major}.{minor + 1}.0" + elif bump_type == "patch": + return f"{major}.{minor}.{patch + 1}" + else: + raise ValueError(f"Invalid bump type: {bump_type}") + + +def update_version_files(new_version): + """Update version in pyproject.toml and __init__.py.""" + print(f"๐Ÿ“ Updating version to {new_version}...") + + # Update pyproject.toml + try: + with open("pyproject.toml", "r", encoding="utf-8") as f: + content = f.read() + + content = re.sub(r'version = "[^"]+"', f'version = "{new_version}"', content) + + with open("pyproject.toml", "w", encoding="utf-8") as f: + f.write(content) + print("โœ… Updated pyproject.toml") + except Exception as e: + print(f"โŒ Failed to update pyproject.toml: {e}") return False + # Update __init__.py + try: + with open("langbase/__init__.py", "r", encoding="utf-8") as f: + content = f.read() + + content = re.sub( + r'__version__ = "[^"]+"', f'__version__ = "{new_version}"', content + ) + + with open("langbase/__init__.py", "w", encoding="utf-8") as f: + f.write(content) + print("โœ… Updated langbase/__init__.py") + except Exception as e: + print(f"โŒ Failed to update langbase/__init__.py: {e}") + return False + + return True + + +def update_changelog(version, release_message): + """Update CHANGELOG.md with new release.""" + print("๐Ÿ“ Updating CHANGELOG.md...") + + try: + # Read current changelog + try: + with open("CHANGELOG.md", "r", encoding="utf-8") as f: + current_content = f.read() + except FileNotFoundError: + current_content = "# Changelog\n\n" + + # Create new entry + date = datetime.now().strftime("%Y-%m-%d") + new_entry = f"## [{version}] - {date}\n\n{release_message}\n\n" + + # Insert after the header + if "# Changelog" in current_content: + parts = current_content.split("# Changelog\n", 1) + updated_content = f"# Changelog\n\n{new_entry}" + ( + parts[1] if len(parts) > 1 else "" + ) + else: + updated_content = f"# Changelog\n\n{new_entry}{current_content}" + + with open("CHANGELOG.md", "w", encoding="utf-8") as f: + f.write(updated_content) + + print("โœ… Updated CHANGELOG.md") + return True + except Exception as e: + print(f"โŒ Failed to update CHANGELOG.md: {e}") + return False + + +def ask_yes_no(question): + """Ask a yes/no question.""" + while True: + try: + answer = input(f"\nโ“ {question} (y/n): ").lower().strip() + if answer in ["y", "yes"]: + return True + elif answer in ["n", "no", ""]: + return False + else: + print("Please answer 'y' or 'n'") + except KeyboardInterrupt: + print("\nโŒ Operation cancelled") + sys.exit(1) + def main(): - """Run the complete release process.""" - print("๐Ÿš€ Starting Langbase SDK release process...\n") + """Run the interactive release process.""" + print("๐Ÿš€ Starting Interactive Langbase SDK Release Process...\n") + + # Ask if this is a test release + test_mode = ask_yes_no( + "Is this a TEST release? (uploads to test.pypi.org instead of PyPI)" + ) + if test_mode: + print("๐Ÿงช TEST MODE: Will upload to test.pypi.org") + + # Get current version + current_version = get_current_version() + print(f"๐Ÿ“‹ Current version: {current_version}") + + # Step 1: Ask for version bump type + print("\n๐Ÿ“ˆ What type of release is this?") + print(" โ€ข patch - Bug fixes, small improvements (0.1.0 โ†’ 0.1.1)") + print(" โ€ข minor - New features, backwards compatible (0.1.0 โ†’ 0.2.0)") + print(" โ€ข major - Breaking changes (0.1.0 โ†’ 1.0.0)") + + while True: + try: + bump_type = ( + input("\nโ“ Enter release type (patch/minor/major): ").lower().strip() + ) + if bump_type in ["patch", "minor", "major"]: + break + else: + print("Please enter 'patch', 'minor', or 'major'") + except KeyboardInterrupt: + print("\nโŒ Release cancelled") + sys.exit(1) + + # Calculate new version + new_version = bump_version(current_version, bump_type) + print(f"\n๐Ÿ“‹ New version will be: {current_version} โ†’ {new_version}") + + # Step 2: Confirm version update + if not ask_yes_no(f"Update version to {new_version}?"): + print("โŒ Release cancelled") + return - # Step 1: Confirm release + # Step 3: Get release message + print(f"\n๐Ÿ“ Enter release message for v{new_version}:") + print(" (Describe what's new, changed, or fixed)") try: - confirm = input("\nโ“ Proceed with release? (y/N): ").lower().strip() - if confirm != "y" and confirm != "yes": - print("โŒ Release cancelled") - return + release_message = input("Release message: ").strip() + if not release_message: + release_message = f"Release v{new_version}" except KeyboardInterrupt: print("\nโŒ Release cancelled") + sys.exit(1) + + # Step 4: Show preview and confirm + print(f"\n๐Ÿ“‹ Release Summary:") + print(f" Version: {current_version} โ†’ {new_version}") + print(f" Type: {bump_type}") + print(f" Message: {release_message}") + if test_mode: + print(" ๐Ÿงช Destination: Test PyPI (test.pypi.org)") + else: + print(" ๐Ÿš€ Destination: Production PyPI (pypi.org)") + + if not ask_yes_no("Proceed with this release?"): + print("โŒ Release cancelled") return - # Step 2: Create version - print("\n๐Ÿ“ฆ Creating new version...") - if not run_command("semantic-release version", "Creating version"): - print("โŒ Failed to create version") + # Step 5: Update version files + if not update_version_files(new_version): + print("โŒ Failed to update version files") sys.exit(1) - # Step 3: Configure git to push tags automatically (one-time setup) - run_command( - "git config push.followTags true", "Configuring git to push tags automatically" - ) + # Step 6: Update changelog + if not update_changelog(new_version, release_message): + print("โŒ Failed to update changelog") + sys.exit(1) - # Step 4: Push everything to origin - print("\nโฌ†๏ธ Pushing to origin...") - if not run_command("git push origin main", "Pushing commits and tags"): - print("โŒ Failed to push to origin") + # Step 7: Handle git commits (skip entirely in test mode) + if test_mode: + print("๐Ÿงช TEST MODE: Skipping all git operations (no commits, no pushes)") + else: + if not ask_yes_no("Commit version changes to git?"): + print("โŒ Release cancelled") + return + + # Commit changes + commit_message = f"๐Ÿš€ RELEASE: v{new_version}\n\n{release_message}" + success, _ = run_command( + f'git add . && git commit -m "{commit_message}"', + "Committing version changes", + ) + if not success: + print("โŒ Failed to commit changes") + sys.exit(1) + + # Step 8: Ask to push to GitHub + if not ask_yes_no("Push changes to GitHub?"): + print("โŒ Skipping GitHub push") + else: + success, _ = run_command("git push origin main", "Pushing to GitHub") + if not success: + print("โŒ Failed to push to GitHub") + sys.exit(1) + + # Step 9: Ask to build package + if not ask_yes_no("Build package for PyPI?"): + print("โŒ Skipping package build") + return + + # Clean previous builds + run_command("rm -rf dist/ build/ *.egg-info/", "Cleaning previous builds") + + # Build package + success, _ = run_command("python -m build", "Building package") + if not success: + print("โŒ Failed to build package") sys.exit(1) - print("\nโœ… Release completed successfully!") - print("๐ŸŽฏ Next steps (optional):") - print(" โ€ข python -m build # Build packages") - print(" โ€ข twine upload dist/* # Upload to PyPI") + # Step 10: Ask to upload to PyPI + upload_destination = "Test PyPI" if test_mode else "PyPI" + if not ask_yes_no(f"Upload to {upload_destination}?"): + print(f"โŒ Skipping {upload_destination} upload") + print(f"โœ… Release v{new_version} prepared successfully!") + if test_mode: + print( + "๐ŸŽฏ To upload to Test PyPI later, run: twine upload --repository testpypi dist/*" + ) + else: + print("๐ŸŽฏ To upload later, run: twine upload dist/*") + return + + # Upload to PyPI or Test PyPI + if test_mode: + upload_cmd = "twine upload --repository testpypi dist/*" + upload_desc = "Uploading to Test PyPI" + else: + upload_cmd = "twine upload dist/*" + upload_desc = "Uploading to PyPI" + + success, _ = run_command(upload_cmd, upload_desc, capture_output=False) + if not success: + print(f"โŒ Failed to upload to {upload_destination}") + sys.exit(1) + + print(f"\n๐ŸŽ‰ Release v{new_version} completed successfully!") + print("โœ… Version updated") + if not test_mode: + print("โœ… Changes committed and pushed to GitHub") + if test_mode: + print("โœ… Package uploaded to Test PyPI") + print("๐Ÿ”— View at: https://test.pypi.org/project/langbase/") + print( + "๐Ÿงช Test install: pip install --index-url https://test.pypi.org/simple/ langbase" + ) + print( + "โš ๏ธ Version files were updated locally but NOT committed - you may want to reset them!" + ) + print( + "๐Ÿ’ก To reset: git checkout -- pyproject.toml langbase/__init__.py CHANGELOG.md" + ) + else: + print("โœ… Package uploaded to PyPI") + print("๐Ÿ”— View at: https://pypi.org/project/langbase/") if __name__ == "__main__": diff --git a/requirements-dev.txt b/requirements-dev.txt index d2ea117..e52401e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,3 +24,4 @@ python-dotenv>=0.19.0 # release python-semantic-release>=8.0.0 +twine>=4.0.0