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.
Files changed (73) hide show
  1. substrai_lambdallm-1.0.0/.github/workflows/ci.yml +54 -0
  2. substrai_lambdallm-1.0.0/.github/workflows/publish.yml +28 -0
  3. substrai_lambdallm-1.0.0/.gitignore +71 -0
  4. substrai_lambdallm-1.0.0/CHANGELOG.md +27 -0
  5. substrai_lambdallm-1.0.0/CONTRIBUTING.md +65 -0
  6. substrai_lambdallm-1.0.0/LICENSE +21 -0
  7. substrai_lambdallm-1.0.0/PKG-INFO +110 -0
  8. substrai_lambdallm-1.0.0/README.md +70 -0
  9. substrai_lambdallm-1.0.0/examples/agent_with_tools.py +97 -0
  10. substrai_lambdallm-1.0.0/examples/basic_summarizer.py +53 -0
  11. substrai_lambdallm-1.0.0/examples/chat_with_memory.py +49 -0
  12. substrai_lambdallm-1.0.0/examples/multi_step_chain.py +97 -0
  13. substrai_lambdallm-1.0.0/examples/streaming_chat.py +43 -0
  14. substrai_lambdallm-1.0.0/pyproject.toml +58 -0
  15. substrai_lambdallm-1.0.0/src/lambdallm/__init__.py +61 -0
  16. substrai_lambdallm-1.0.0/src/lambdallm/agents/__init__.py +11 -0
  17. substrai_lambdallm-1.0.0/src/lambdallm/agents/agent.py +315 -0
  18. substrai_lambdallm-1.0.0/src/lambdallm/agents/async_tools.py +243 -0
  19. substrai_lambdallm-1.0.0/src/lambdallm/agents/router.py +132 -0
  20. substrai_lambdallm-1.0.0/src/lambdallm/agents/sandbox.py +132 -0
  21. substrai_lambdallm-1.0.0/src/lambdallm/agents/tool.py +259 -0
  22. substrai_lambdallm-1.0.0/src/lambdallm/chains/__init__.py +10 -0
  23. substrai_lambdallm-1.0.0/src/lambdallm/chains/chain.py +123 -0
  24. substrai_lambdallm-1.0.0/src/lambdallm/chains/runner.py +222 -0
  25. substrai_lambdallm-1.0.0/src/lambdallm/cli/__init__.py +1 -0
  26. substrai_lambdallm-1.0.0/src/lambdallm/cli/dev.py +168 -0
  27. substrai_lambdallm-1.0.0/src/lambdallm/cli/init.py +331 -0
  28. substrai_lambdallm-1.0.0/src/lambdallm/cli/main.py +298 -0
  29. substrai_lambdallm-1.0.0/src/lambdallm/core/__init__.py +0 -0
  30. substrai_lambdallm-1.0.0/src/lambdallm/core/config.py +250 -0
  31. substrai_lambdallm-1.0.0/src/lambdallm/core/context.py +227 -0
  32. substrai_lambdallm-1.0.0/src/lambdallm/core/exceptions.py +45 -0
  33. substrai_lambdallm-1.0.0/src/lambdallm/core/handler.py +195 -0
  34. substrai_lambdallm-1.0.0/src/lambdallm/core/models.py +52 -0
  35. substrai_lambdallm-1.0.0/src/lambdallm/core/prompt.py +194 -0
  36. substrai_lambdallm-1.0.0/src/lambdallm/core/streaming.py +151 -0
  37. substrai_lambdallm-1.0.0/src/lambdallm/deploy/__init__.py +10 -0
  38. substrai_lambdallm-1.0.0/src/lambdallm/deploy/canary.py +179 -0
  39. substrai_lambdallm-1.0.0/src/lambdallm/deploy/deployer.py +362 -0
  40. substrai_lambdallm-1.0.0/src/lambdallm/deploy/generator.py +334 -0
  41. substrai_lambdallm-1.0.0/src/lambdallm/middleware/__init__.py +12 -0
  42. substrai_lambdallm-1.0.0/src/lambdallm/middleware/base.py +62 -0
  43. substrai_lambdallm-1.0.0/src/lambdallm/middleware/cost.py +87 -0
  44. substrai_lambdallm-1.0.0/src/lambdallm/middleware/logging.py +80 -0
  45. substrai_lambdallm-1.0.0/src/lambdallm/observability/__init__.py +11 -0
  46. substrai_lambdallm-1.0.0/src/lambdallm/observability/ab_testing.py +178 -0
  47. substrai_lambdallm-1.0.0/src/lambdallm/observability/cost_tracker.py +311 -0
  48. substrai_lambdallm-1.0.0/src/lambdallm/observability/metrics.py +216 -0
  49. substrai_lambdallm-1.0.0/src/lambdallm/observability/prompt_analytics.py +207 -0
  50. substrai_lambdallm-1.0.0/src/lambdallm/observability/router.py +182 -0
  51. substrai_lambdallm-1.0.0/src/lambdallm/observability/tracer.py +220 -0
  52. substrai_lambdallm-1.0.0/src/lambdallm/providers/__init__.py +28 -0
  53. substrai_lambdallm-1.0.0/src/lambdallm/providers/base.py +54 -0
  54. substrai_lambdallm-1.0.0/src/lambdallm/providers/bedrock.py +177 -0
  55. substrai_lambdallm-1.0.0/src/lambdallm/state/__init__.py +10 -0
  56. substrai_lambdallm-1.0.0/src/lambdallm/state/auto_session.py +111 -0
  57. substrai_lambdallm-1.0.0/src/lambdallm/state/context_window.py +187 -0
  58. substrai_lambdallm-1.0.0/src/lambdallm/state/dynamodb.py +113 -0
  59. substrai_lambdallm-1.0.0/src/lambdallm/state/memory.py +51 -0
  60. substrai_lambdallm-1.0.0/src/lambdallm/state/session.py +172 -0
  61. substrai_lambdallm-1.0.0/src/lambdallm/testing/__init__.py +10 -0
  62. substrai_lambdallm-1.0.0/src/lambdallm/testing/golden.py +234 -0
  63. substrai_lambdallm-1.0.0/src/lambdallm/testing/mocks.py +98 -0
  64. substrai_lambdallm-1.0.0/tests/__init__.py +0 -0
  65. substrai_lambdallm-1.0.0/tests/test_agents.py +186 -0
  66. substrai_lambdallm-1.0.0/tests/test_chains.py +134 -0
  67. substrai_lambdallm-1.0.0/tests/test_config.py +47 -0
  68. substrai_lambdallm-1.0.0/tests/test_handler.py +119 -0
  69. substrai_lambdallm-1.0.0/tests/test_models.py +40 -0
  70. substrai_lambdallm-1.0.0/tests/test_observability.py +177 -0
  71. substrai_lambdallm-1.0.0/tests/test_prompt.py +85 -0
  72. substrai_lambdallm-1.0.0/tests/test_session.py +105 -0
  73. 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
+ }