substrai-lambdallm 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- substrai_lambdallm-1.0.0/.github/workflows/ci.yml +54 -0
- substrai_lambdallm-1.0.0/.github/workflows/publish.yml +28 -0
- substrai_lambdallm-1.0.0/.gitignore +71 -0
- substrai_lambdallm-1.0.0/CHANGELOG.md +27 -0
- substrai_lambdallm-1.0.0/CONTRIBUTING.md +65 -0
- substrai_lambdallm-1.0.0/LICENSE +21 -0
- substrai_lambdallm-1.0.0/PKG-INFO +110 -0
- substrai_lambdallm-1.0.0/README.md +70 -0
- substrai_lambdallm-1.0.0/examples/agent_with_tools.py +97 -0
- substrai_lambdallm-1.0.0/examples/basic_summarizer.py +53 -0
- substrai_lambdallm-1.0.0/examples/chat_with_memory.py +49 -0
- substrai_lambdallm-1.0.0/examples/multi_step_chain.py +97 -0
- substrai_lambdallm-1.0.0/examples/streaming_chat.py +43 -0
- substrai_lambdallm-1.0.0/pyproject.toml +58 -0
- substrai_lambdallm-1.0.0/src/lambdallm/__init__.py +61 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/__init__.py +11 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/agent.py +315 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/async_tools.py +243 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/router.py +132 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/sandbox.py +132 -0
- substrai_lambdallm-1.0.0/src/lambdallm/agents/tool.py +259 -0
- substrai_lambdallm-1.0.0/src/lambdallm/chains/__init__.py +10 -0
- substrai_lambdallm-1.0.0/src/lambdallm/chains/chain.py +123 -0
- substrai_lambdallm-1.0.0/src/lambdallm/chains/runner.py +222 -0
- substrai_lambdallm-1.0.0/src/lambdallm/cli/__init__.py +1 -0
- substrai_lambdallm-1.0.0/src/lambdallm/cli/dev.py +168 -0
- substrai_lambdallm-1.0.0/src/lambdallm/cli/init.py +331 -0
- substrai_lambdallm-1.0.0/src/lambdallm/cli/main.py +298 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/__init__.py +0 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/config.py +250 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/context.py +227 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/exceptions.py +45 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/handler.py +195 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/models.py +52 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/prompt.py +194 -0
- substrai_lambdallm-1.0.0/src/lambdallm/core/streaming.py +151 -0
- substrai_lambdallm-1.0.0/src/lambdallm/deploy/__init__.py +10 -0
- substrai_lambdallm-1.0.0/src/lambdallm/deploy/canary.py +179 -0
- substrai_lambdallm-1.0.0/src/lambdallm/deploy/deployer.py +362 -0
- substrai_lambdallm-1.0.0/src/lambdallm/deploy/generator.py +334 -0
- substrai_lambdallm-1.0.0/src/lambdallm/middleware/__init__.py +12 -0
- substrai_lambdallm-1.0.0/src/lambdallm/middleware/base.py +62 -0
- substrai_lambdallm-1.0.0/src/lambdallm/middleware/cost.py +87 -0
- substrai_lambdallm-1.0.0/src/lambdallm/middleware/logging.py +80 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/__init__.py +11 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/ab_testing.py +178 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/cost_tracker.py +311 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/metrics.py +216 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/prompt_analytics.py +207 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/router.py +182 -0
- substrai_lambdallm-1.0.0/src/lambdallm/observability/tracer.py +220 -0
- substrai_lambdallm-1.0.0/src/lambdallm/providers/__init__.py +28 -0
- substrai_lambdallm-1.0.0/src/lambdallm/providers/base.py +54 -0
- substrai_lambdallm-1.0.0/src/lambdallm/providers/bedrock.py +177 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/__init__.py +10 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/auto_session.py +111 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/context_window.py +187 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/dynamodb.py +113 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/memory.py +51 -0
- substrai_lambdallm-1.0.0/src/lambdallm/state/session.py +172 -0
- substrai_lambdallm-1.0.0/src/lambdallm/testing/__init__.py +10 -0
- substrai_lambdallm-1.0.0/src/lambdallm/testing/golden.py +234 -0
- substrai_lambdallm-1.0.0/src/lambdallm/testing/mocks.py +98 -0
- substrai_lambdallm-1.0.0/tests/__init__.py +0 -0
- substrai_lambdallm-1.0.0/tests/test_agents.py +186 -0
- substrai_lambdallm-1.0.0/tests/test_chains.py +134 -0
- substrai_lambdallm-1.0.0/tests/test_config.py +47 -0
- substrai_lambdallm-1.0.0/tests/test_handler.py +119 -0
- substrai_lambdallm-1.0.0/tests/test_models.py +40 -0
- substrai_lambdallm-1.0.0/tests/test_observability.py +177 -0
- substrai_lambdallm-1.0.0/tests/test_prompt.py +85 -0
- substrai_lambdallm-1.0.0/tests/test_session.py +105 -0
- substrai_lambdallm-1.0.0/tests/test_streaming.py +60 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: ruff check src/ tests/
|
|
31
|
+
|
|
32
|
+
- name: Run tests
|
|
33
|
+
run: pytest tests/ -v --tb=short
|
|
34
|
+
|
|
35
|
+
build:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
needs: test
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Set up Python
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.12"
|
|
45
|
+
|
|
46
|
+
- name: Build package
|
|
47
|
+
run: |
|
|
48
|
+
pip install build
|
|
49
|
+
python -m build
|
|
50
|
+
|
|
51
|
+
- name: Verify package
|
|
52
|
+
run: |
|
|
53
|
+
pip install dist/*.whl
|
|
54
|
+
python -c "import lambdallm; print(f'LambdaLLM v{lambdallm.__version__}')"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: release
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: |
|
|
24
|
+
pip install build
|
|
25
|
+
python -m build
|
|
26
|
+
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
build/
|
|
7
|
+
develop-eggs/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
lib/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.installed.cfg
|
|
20
|
+
*.egg
|
|
21
|
+
*.manifest
|
|
22
|
+
*.spec
|
|
23
|
+
pip-log.txt
|
|
24
|
+
pip-delete-this-directory.txt
|
|
25
|
+
htmlcov/
|
|
26
|
+
.tox/
|
|
27
|
+
.nox/
|
|
28
|
+
.coverage
|
|
29
|
+
.coverage.*
|
|
30
|
+
.cache
|
|
31
|
+
nosetests.xml
|
|
32
|
+
coverage.xml
|
|
33
|
+
*.cover
|
|
34
|
+
*.py,cover
|
|
35
|
+
.hypothesis/
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
cover/
|
|
38
|
+
*.log
|
|
39
|
+
local_settings.py
|
|
40
|
+
db.sqlite3
|
|
41
|
+
db.sqlite3-journal
|
|
42
|
+
instance/
|
|
43
|
+
.webassets-cache
|
|
44
|
+
.scrapy
|
|
45
|
+
docs/_build/
|
|
46
|
+
.pybuilder/
|
|
47
|
+
target/
|
|
48
|
+
.ipynb_checkpoints
|
|
49
|
+
profile_default/
|
|
50
|
+
ipython_config.py
|
|
51
|
+
.pdm.toml
|
|
52
|
+
.pdm-python.txt
|
|
53
|
+
__pypackages__/
|
|
54
|
+
celerybeat-schedule
|
|
55
|
+
celerybeat.pid
|
|
56
|
+
*.sage.py
|
|
57
|
+
.env
|
|
58
|
+
.venv
|
|
59
|
+
env/
|
|
60
|
+
venv/
|
|
61
|
+
ENV/
|
|
62
|
+
.spyderproject
|
|
63
|
+
.spyproject
|
|
64
|
+
.ropeproject
|
|
65
|
+
/site
|
|
66
|
+
.mypy_cache/
|
|
67
|
+
.dmypy.json
|
|
68
|
+
dmypy.json
|
|
69
|
+
.pyre/
|
|
70
|
+
.pytype/
|
|
71
|
+
cython_debug/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to LambdaLLM will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-05-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `@handler` decorator with IoC pattern for Lambda functions
|
|
12
|
+
- `Prompt` class with type-safe templates and structured output
|
|
13
|
+
- `Model` enum with Bedrock model IDs (Claude, Titan, Llama)
|
|
14
|
+
- `BedrockProvider` with lazy initialization and cost tracking
|
|
15
|
+
- Middleware system: `LoggingMiddleware`, `CostTrackingMiddleware`
|
|
16
|
+
- Retry with exponential backoff and fallback model support
|
|
17
|
+
- Timeout awareness with checkpoint/truncate/fail-fast strategies
|
|
18
|
+
- GitHub Actions CI/CD (test + publish)
|
|
19
|
+
- Examples: basic summarizer, chat with memory
|
|
20
|
+
- Full test suite with mocked providers
|
|
21
|
+
|
|
22
|
+
### Architecture
|
|
23
|
+
- Core package size: < 50KB (no dependencies in core)
|
|
24
|
+
- Plugin-based provider system (BaseProvider interface)
|
|
25
|
+
- Middleware pipeline (before/after hooks)
|
|
26
|
+
- Convention over configuration (works with zero config)
|
|
27
|
+
- Escape hatch: `context.get_raw_client()` for direct boto3 access
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Contributing to LambdaLLM
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to LambdaLLM! This document provides guidelines for contributing.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/lambdallm.git`
|
|
9
|
+
3. Create a virtual environment: `python -m venv .venv && source .venv/bin/activate`
|
|
10
|
+
4. Install dev dependencies: `pip install -e ".[dev]"`
|
|
11
|
+
5. Create a branch: `git checkout -b feat/your-feature`
|
|
12
|
+
|
|
13
|
+
## Development Workflow
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Run tests
|
|
17
|
+
pytest tests/ -v
|
|
18
|
+
|
|
19
|
+
# Run linter
|
|
20
|
+
ruff check src/ tests/
|
|
21
|
+
|
|
22
|
+
# Format code
|
|
23
|
+
ruff format src/ tests/
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Commit Messages
|
|
27
|
+
|
|
28
|
+
We follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
29
|
+
|
|
30
|
+
- `feat:` New feature
|
|
31
|
+
- `fix:` Bug fix
|
|
32
|
+
- `docs:` Documentation
|
|
33
|
+
- `test:` Tests
|
|
34
|
+
- `ci:` CI/CD changes
|
|
35
|
+
- `refactor:` Code refactoring
|
|
36
|
+
- `chore:` Maintenance
|
|
37
|
+
|
|
38
|
+
## Pull Request Process
|
|
39
|
+
|
|
40
|
+
1. Ensure all tests pass
|
|
41
|
+
2. Update documentation if needed
|
|
42
|
+
3. Add tests for new features
|
|
43
|
+
4. Keep PRs focused — one feature per PR
|
|
44
|
+
5. Reference any related issues
|
|
45
|
+
|
|
46
|
+
## Code Style
|
|
47
|
+
|
|
48
|
+
- Python 3.10+ type hints
|
|
49
|
+
- Docstrings on all public functions/classes
|
|
50
|
+
- Max line length: 100 characters
|
|
51
|
+
- Use `ruff` for linting and formatting
|
|
52
|
+
|
|
53
|
+
## Architecture Principles
|
|
54
|
+
|
|
55
|
+
When contributing, keep these framework principles in mind:
|
|
56
|
+
|
|
57
|
+
1. **Convention over configuration** — sensible defaults everywhere
|
|
58
|
+
2. **< 5MB package size** — no heavy dependencies in core
|
|
59
|
+
3. **Lambda-first** — every feature must work within Lambda constraints
|
|
60
|
+
4. **Observable by default** — log and trace without user configuration
|
|
61
|
+
5. **Escape hatches** — never trap the user
|
|
62
|
+
|
|
63
|
+
## Questions?
|
|
64
|
+
|
|
65
|
+
Open a [Discussion](https://github.com/substrai/lambdallm/discussions) or reach out at contact@substrai.dev.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SubStrai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: substrai-lambdallm
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Serverless-native LLM orchestration framework for AWS Lambda
|
|
5
|
+
Project-URL: Homepage, https://substrai.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/substrai/lambdallm
|
|
7
|
+
Project-URL: Documentation, https://docs.substrai.dev/lambdallm
|
|
8
|
+
Project-URL: Issues, https://github.com/substrai/lambdallm/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/substrai/lambdallm/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Gaurav Kumar Sinha <gaurav@substrai.dev>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: agents,aws,bedrock,chains,framework,genai,lambda,llm,serverless
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: aws-xray-sdk>=2.12.0; extra == 'all'
|
|
26
|
+
Requires-Dist: boto3>=1.28.0; extra == 'all'
|
|
27
|
+
Requires-Dist: pyyaml>=6.0; extra == 'all'
|
|
28
|
+
Provides-Extra: bedrock
|
|
29
|
+
Requires-Dist: boto3>=1.28.0; extra == 'bedrock'
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: moto>=4.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
35
|
+
Provides-Extra: xray
|
|
36
|
+
Requires-Dist: aws-xray-sdk>=2.12.0; extra == 'xray'
|
|
37
|
+
Provides-Extra: yaml
|
|
38
|
+
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# LambdaLLM
|
|
42
|
+
|
|
43
|
+
**Serverless-native LLM orchestration framework for AWS Lambda.**
|
|
44
|
+
|
|
45
|
+
> Built by [SubstrAI](https://github.com/substrai) — Open-source GenAI frameworks for serverless infrastructure.
|
|
46
|
+
|
|
47
|
+
## The Problem
|
|
48
|
+
|
|
49
|
+
Existing LLM frameworks (LangChain, LlamaIndex) assume long-running servers. They break on Lambda:
|
|
50
|
+
- Cold starts: 500MB+ dependency trees add seconds
|
|
51
|
+
- Stateless: No conversation memory between invocations
|
|
52
|
+
- 15-min timeout: Long agent loops crash
|
|
53
|
+
- 250MB limit: LangChain alone exceeds this
|
|
54
|
+
|
|
55
|
+
## The Solution
|
|
56
|
+
|
|
57
|
+
LambdaLLM is purpose-built for Lambda's constraints:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from lambdallm import handler, Prompt, Model
|
|
61
|
+
|
|
62
|
+
summarize = Prompt(
|
|
63
|
+
template="Summarize in {max_words} words:\n\n{document}",
|
|
64
|
+
output_schema={"summary": str, "key_points": list}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@handler(model=Model.CLAUDE_3_HAIKU)
|
|
68
|
+
def lambda_handler(event, context):
|
|
69
|
+
return summarize.invoke(
|
|
70
|
+
document=event["body"]["text"],
|
|
71
|
+
max_words=100
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Features
|
|
76
|
+
|
|
77
|
+
- **< 5MB** package size (vs 400MB+ for LangChain)
|
|
78
|
+
- **Cold-start optimized** — lazy imports, connection pooling
|
|
79
|
+
- **DynamoDB-native state** — conversation memory that survives stateless execution
|
|
80
|
+
- **Cost-aware routing** — auto-select cheapest model that meets quality threshold
|
|
81
|
+
- **One-command deploy** — `lambdallm deploy` generates all AWS infrastructure
|
|
82
|
+
- **Timeout handling** — checkpoint/resume for long chains
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install lambdallm[bedrock]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Quick Start
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
lambdallm init my-project
|
|
94
|
+
cd my-project
|
|
95
|
+
lambdallm dev
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
- [Getting Started](https://docs.substrai.dev/lambdallm/getting-started)
|
|
101
|
+
- [API Reference](https://docs.substrai.dev/lambdallm/api)
|
|
102
|
+
- [Examples](https://github.com/substrai/lambdallm/tree/main/examples)
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT — see [LICENSE](LICENSE)
|
|
107
|
+
|
|
108
|
+
## Author
|
|
109
|
+
|
|
110
|
+
**Gaurav Kumar Sinha** — Founder, [SubstrAI](https://github.com/substrai)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# LambdaLLM
|
|
2
|
+
|
|
3
|
+
**Serverless-native LLM orchestration framework for AWS Lambda.**
|
|
4
|
+
|
|
5
|
+
> Built by [SubstrAI](https://github.com/substrai) — Open-source GenAI frameworks for serverless infrastructure.
|
|
6
|
+
|
|
7
|
+
## The Problem
|
|
8
|
+
|
|
9
|
+
Existing LLM frameworks (LangChain, LlamaIndex) assume long-running servers. They break on Lambda:
|
|
10
|
+
- Cold starts: 500MB+ dependency trees add seconds
|
|
11
|
+
- Stateless: No conversation memory between invocations
|
|
12
|
+
- 15-min timeout: Long agent loops crash
|
|
13
|
+
- 250MB limit: LangChain alone exceeds this
|
|
14
|
+
|
|
15
|
+
## The Solution
|
|
16
|
+
|
|
17
|
+
LambdaLLM is purpose-built for Lambda's constraints:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from lambdallm import handler, Prompt, Model
|
|
21
|
+
|
|
22
|
+
summarize = Prompt(
|
|
23
|
+
template="Summarize in {max_words} words:\n\n{document}",
|
|
24
|
+
output_schema={"summary": str, "key_points": list}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@handler(model=Model.CLAUDE_3_HAIKU)
|
|
28
|
+
def lambda_handler(event, context):
|
|
29
|
+
return summarize.invoke(
|
|
30
|
+
document=event["body"]["text"],
|
|
31
|
+
max_words=100
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **< 5MB** package size (vs 400MB+ for LangChain)
|
|
38
|
+
- **Cold-start optimized** — lazy imports, connection pooling
|
|
39
|
+
- **DynamoDB-native state** — conversation memory that survives stateless execution
|
|
40
|
+
- **Cost-aware routing** — auto-select cheapest model that meets quality threshold
|
|
41
|
+
- **One-command deploy** — `lambdallm deploy` generates all AWS infrastructure
|
|
42
|
+
- **Timeout handling** — checkpoint/resume for long chains
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install lambdallm[bedrock]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
lambdallm init my-project
|
|
54
|
+
cd my-project
|
|
55
|
+
lambdallm dev
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Documentation
|
|
59
|
+
|
|
60
|
+
- [Getting Started](https://docs.substrai.dev/lambdallm/getting-started)
|
|
61
|
+
- [API Reference](https://docs.substrai.dev/lambdallm/api)
|
|
62
|
+
- [Examples](https://github.com/substrai/lambdallm/tree/main/examples)
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT — see [LICENSE](LICENSE)
|
|
67
|
+
|
|
68
|
+
## Author
|
|
69
|
+
|
|
70
|
+
**Gaurav Kumar Sinha** — Founder, [SubstrAI](https://github.com/substrai)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Example: AI agent with tools for research and analysis.
|
|
2
|
+
|
|
3
|
+
Demonstrates how to build a ReAct-style agent that uses tools
|
|
4
|
+
to answer complex questions, all within Lambda's constraints.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from lambdallm import handler, Model
|
|
8
|
+
from lambdallm.agents import Tool, Agent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Define tools the agent can use
|
|
12
|
+
@Tool(description="Search the knowledge base for relevant documents")
|
|
13
|
+
def search_kb(query: str, max_results: int = 3) -> list[dict]:
|
|
14
|
+
"""Search for documents matching the query.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
query: The search query string.
|
|
18
|
+
max_results: Maximum number of results to return.
|
|
19
|
+
"""
|
|
20
|
+
# In production, this would call OpenSearch, Bedrock KB, etc.
|
|
21
|
+
return [
|
|
22
|
+
{"title": f"Result for '{query}'", "content": f"Relevant information about {query}..."},
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@Tool(description="Calculate a mathematical expression")
|
|
27
|
+
def calculate(expression: str) -> float:
|
|
28
|
+
"""Safely evaluate a mathematical expression.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
expression: Mathematical expression to evaluate (e.g., '2 + 2', '100 * 0.15').
|
|
32
|
+
"""
|
|
33
|
+
# Safe eval for basic math
|
|
34
|
+
allowed_chars = set("0123456789+-*/.() ")
|
|
35
|
+
if not all(c in allowed_chars for c in expression):
|
|
36
|
+
raise ValueError(f"Invalid expression: {expression}")
|
|
37
|
+
return eval(expression)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@Tool(description="Get current date and time")
|
|
41
|
+
def get_current_time() -> str:
|
|
42
|
+
"""Get the current UTC date and time."""
|
|
43
|
+
from datetime import datetime, timezone
|
|
44
|
+
return datetime.now(timezone.utc).isoformat()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Create the agent
|
|
48
|
+
research_agent = Agent(
|
|
49
|
+
name="research-analyst",
|
|
50
|
+
system_prompt="""You are a research analyst. Use the available tools to
|
|
51
|
+
gather information and perform calculations to answer questions accurately.
|
|
52
|
+
Always cite your sources and show your work for calculations.""",
|
|
53
|
+
tools=[search_kb, calculate, get_current_time],
|
|
54
|
+
max_iterations=5,
|
|
55
|
+
timeout_buffer=30, # Reserve 30s before Lambda timeout
|
|
56
|
+
max_cost_usd=0.10, # Stop if cost exceeds $0.10
|
|
57
|
+
verbose=True,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@handler(model=Model.CLAUDE_3_SONNET)
|
|
62
|
+
def lambda_handler(event, context):
|
|
63
|
+
"""Research agent Lambda handler.
|
|
64
|
+
|
|
65
|
+
Expected event body:
|
|
66
|
+
{
|
|
67
|
+
"question": "What is the total revenue if we grow 15% from $1M?"
|
|
68
|
+
}
|
|
69
|
+
"""
|
|
70
|
+
import json
|
|
71
|
+
|
|
72
|
+
body = json.loads(event.get("body", "{}")) if isinstance(event.get("body"), str) else event.get("body", {})
|
|
73
|
+
|
|
74
|
+
question = body.get("question", "")
|
|
75
|
+
|
|
76
|
+
# Run the agent
|
|
77
|
+
result = research_agent.run(query=question, context=context)
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
"statusCode": 200,
|
|
81
|
+
"body": {
|
|
82
|
+
"answer": result.answer,
|
|
83
|
+
"status": result.status,
|
|
84
|
+
"iterations": result.total_iterations,
|
|
85
|
+
"tool_calls": result.total_tool_calls,
|
|
86
|
+
"cost_usd": result.total_cost_usd,
|
|
87
|
+
"latency_ms": result.total_latency_ms,
|
|
88
|
+
"steps": [
|
|
89
|
+
{
|
|
90
|
+
"thought": s.thought[:200],
|
|
91
|
+
"tool": s.tool_name,
|
|
92
|
+
"tool_output": str(s.tool_output)[:200] if s.tool_output else None,
|
|
93
|
+
}
|
|
94
|
+
for s in result.steps
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Example: Basic document summarizer using LambdaLLM.
|
|
2
|
+
|
|
3
|
+
Deploy this as a Lambda function to get a GenAI-powered
|
|
4
|
+
summarization API in under 5 minutes.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
lambdallm init --template basic
|
|
8
|
+
lambdallm deploy
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from lambdallm import handler, Prompt, Model
|
|
12
|
+
|
|
13
|
+
# Define a reusable, type-safe prompt
|
|
14
|
+
summarize = Prompt(
|
|
15
|
+
name="summarize",
|
|
16
|
+
template="""Summarize the following document in {max_words} words or less.
|
|
17
|
+
Focus on the key points and main conclusions.
|
|
18
|
+
|
|
19
|
+
Document:
|
|
20
|
+
{document}""",
|
|
21
|
+
input_schema={"document": str, "max_words": int},
|
|
22
|
+
output_schema={"summary": str, "key_points": list},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@handler(model=Model.CLAUDE_3_HAIKU, timeout_strategy="truncate")
|
|
27
|
+
def lambda_handler(event, context):
|
|
28
|
+
"""Lambda handler for document summarization.
|
|
29
|
+
|
|
30
|
+
Expected event body:
|
|
31
|
+
{
|
|
32
|
+
"text": "The document to summarize...",
|
|
33
|
+
"max_words": 100
|
|
34
|
+
}
|
|
35
|
+
"""
|
|
36
|
+
import json
|
|
37
|
+
|
|
38
|
+
body = json.loads(event.get("body", "{}")) if isinstance(event.get("body"), str) else event.get("body", {})
|
|
39
|
+
|
|
40
|
+
result = summarize.invoke(
|
|
41
|
+
_context=context,
|
|
42
|
+
document=body.get("text", ""),
|
|
43
|
+
max_words=body.get("max_words", 100),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
"statusCode": 200,
|
|
48
|
+
"body": {
|
|
49
|
+
"result": result,
|
|
50
|
+
"cost_usd": context.total_cost,
|
|
51
|
+
"model": context.model.model_id,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Example: Multi-turn chat with conversation memory.
|
|
2
|
+
|
|
3
|
+
Demonstrates how LambdaLLM handles stateless Lambda + stateful conversations
|
|
4
|
+
using DynamoDB-backed session management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from lambdallm import handler, Model
|
|
8
|
+
from lambdallm.core.context import LambdaLLMContext
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@handler(
|
|
12
|
+
model=Model.CLAUDE_3_SONNET,
|
|
13
|
+
timeout_strategy="fail-fast",
|
|
14
|
+
timeout_buffer=10,
|
|
15
|
+
)
|
|
16
|
+
def lambda_handler(event, context: LambdaLLMContext):
|
|
17
|
+
"""Multi-turn chat handler.
|
|
18
|
+
|
|
19
|
+
Expected event body:
|
|
20
|
+
{
|
|
21
|
+
"message": "User's message",
|
|
22
|
+
"session_id": "unique-session-id"
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
25
|
+
import json
|
|
26
|
+
|
|
27
|
+
body = json.loads(event.get("body", "{}")) if isinstance(event.get("body"), str) else event.get("body", {})
|
|
28
|
+
|
|
29
|
+
user_message = body.get("message", "")
|
|
30
|
+
session_id = body.get("session_id", "default")
|
|
31
|
+
|
|
32
|
+
# In Phase 2, this will auto-load from DynamoDB:
|
|
33
|
+
# session = context.session # auto-loaded via session_id
|
|
34
|
+
|
|
35
|
+
# For now, simple single-turn response
|
|
36
|
+
response = context.invoke(
|
|
37
|
+
"You are a helpful assistant. Respond to: {message}",
|
|
38
|
+
message=user_message,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
"statusCode": 200,
|
|
43
|
+
"body": {
|
|
44
|
+
"reply": response,
|
|
45
|
+
"session_id": session_id,
|
|
46
|
+
"cost_usd": context.total_cost,
|
|
47
|
+
"remaining_time_ms": context.remaining_time_ms,
|
|
48
|
+
},
|
|
49
|
+
}
|