runlet 0.1.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 (55) hide show
  1. runlet-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
  2. runlet-0.1.0/.github/ISSUE_TEMPLATE/design_discussion.md +18 -0
  3. runlet-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. runlet-0.1.0/.github/pull_request_template.md +17 -0
  5. runlet-0.1.0/.github/workflows/ci.yml +28 -0
  6. runlet-0.1.0/.github/workflows/publish.yml +76 -0
  7. runlet-0.1.0/.gitignore +15 -0
  8. runlet-0.1.0/AGENTS.md +73 -0
  9. runlet-0.1.0/CHANGELOG.md +10 -0
  10. runlet-0.1.0/CODE_OF_CONDUCT.md +15 -0
  11. runlet-0.1.0/CONTRIBUTING.md +33 -0
  12. runlet-0.1.0/LICENSE +22 -0
  13. runlet-0.1.0/PKG-INFO +256 -0
  14. runlet-0.1.0/README.md +232 -0
  15. runlet-0.1.0/SECURITY.md +27 -0
  16. runlet-0.1.0/docs/architecture.md +62 -0
  17. runlet-0.1.0/docs/comparison.md +30 -0
  18. runlet-0.1.0/docs/design-principles.md +33 -0
  19. runlet-0.1.0/docs/roadmap.md +29 -0
  20. runlet-0.1.0/pyproject.toml +51 -0
  21. runlet-0.1.0/src/runlet/__init__.py +87 -0
  22. runlet-0.1.0/src/runlet/core/__init__.py +52 -0
  23. runlet-0.1.0/src/runlet/core/agent.py +18 -0
  24. runlet-0.1.0/src/runlet/core/errors.py +34 -0
  25. runlet-0.1.0/src/runlet/core/events.py +51 -0
  26. runlet-0.1.0/src/runlet/core/messages.py +47 -0
  27. runlet-0.1.0/src/runlet/core/models.py +130 -0
  28. runlet-0.1.0/src/runlet/core/runs.py +82 -0
  29. runlet-0.1.0/src/runlet/integrations/__init__.py +13 -0
  30. runlet-0.1.0/src/runlet/integrations/hooks.py +50 -0
  31. runlet-0.1.0/src/runlet/integrations/tools.py +77 -0
  32. runlet-0.1.0/src/runlet/providers/__init__.py +5 -0
  33. runlet-0.1.0/src/runlet/providers/openai.py +156 -0
  34. runlet-0.1.0/src/runlet/py.typed +1 -0
  35. runlet-0.1.0/src/runlet/runtime/__init__.py +20 -0
  36. runlet-0.1.0/src/runlet/runtime/context.py +48 -0
  37. runlet-0.1.0/src/runlet/runtime/engine.py +255 -0
  38. runlet-0.1.0/src/runlet/runtime/policies.py +23 -0
  39. runlet-0.1.0/src/runlet/runtime/state.py +29 -0
  40. runlet-0.1.0/src/runlet/testing/__init__.py +6 -0
  41. runlet-0.1.0/src/runlet/testing/fakes.py +56 -0
  42. runlet-0.1.0/tests/test_context.py +25 -0
  43. runlet-0.1.0/tests/test_core.py +74 -0
  44. runlet-0.1.0/tests/test_events.py +26 -0
  45. runlet-0.1.0/tests/test_hooks.py +39 -0
  46. runlet-0.1.0/tests/test_models.py +43 -0
  47. runlet-0.1.0/tests/test_openai_provider.py +212 -0
  48. runlet-0.1.0/tests/test_package_layout.py +14 -0
  49. runlet-0.1.0/tests/test_public_api.py +23 -0
  50. runlet-0.1.0/tests/test_runtime_basic.py +25 -0
  51. runlet-0.1.0/tests/test_runtime_streaming.py +22 -0
  52. runlet-0.1.0/tests/test_runtime_streaming_tools.py +92 -0
  53. runlet-0.1.0/tests/test_runtime_tools.py +37 -0
  54. runlet-0.1.0/tests/test_state.py +24 -0
  55. runlet-0.1.0/tests/test_tools.py +53 -0
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report incorrect runtime behavior
4
+ labels: bug
5
+ ---
6
+
7
+ ## Summary
8
+
9
+ Describe the bug.
10
+
11
+ ## Expected Behavior
12
+
13
+ What should happen?
14
+
15
+ ## Actual Behavior
16
+
17
+ What happened instead?
18
+
19
+ ## Reproduction
20
+
21
+ Provide the smallest code sample or steps that reproduce the issue.
22
+
23
+ ## Environment
24
+
25
+ - Python version:
26
+ - Runlet version or commit:
27
+ - Operating system:
28
+
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: Design discussion
3
+ about: Discuss runtime architecture, extension points, or tradeoffs
4
+ labels: design
5
+ ---
6
+
7
+ ## Topic
8
+
9
+ What design area should be discussed?
10
+
11
+ ## Context
12
+
13
+ What constraints or prior decisions matter?
14
+
15
+ ## Options
16
+
17
+ List the reasonable options and tradeoffs.
18
+
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Feature request
3
+ about: Propose a focused runtime capability
4
+ labels: enhancement
5
+ ---
6
+
7
+ ## Problem
8
+
9
+ What concrete problem should this solve?
10
+
11
+ ## Proposed Shape
12
+
13
+ Describe the smallest API or behavior that would solve it.
14
+
15
+ ## Scope Check
16
+
17
+ Does this belong in the runtime core, or should it be an adapter/application
18
+ feature?
19
+
@@ -0,0 +1,17 @@
1
+ ## Summary
2
+
3
+ What changed and why?
4
+
5
+ ## Runtime Impact
6
+
7
+ Does this affect execution flow, context budgeting, hooks, tools, models, state,
8
+ or events?
9
+
10
+ ## Observability Impact
11
+
12
+ Does this add, remove, or change emitted events or trace data?
13
+
14
+ ## Verification
15
+
16
+ What command did you run?
17
+
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Python ${{ matrix.python-version }}
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12"]
17
+
18
+ steps:
19
+ - name: Checkout
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Run tests
28
+ run: PYTHONPATH=src python3 -m unittest discover tests
@@ -0,0 +1,76 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build distribution
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout
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: Verify tag matches package version
23
+ run: |
24
+ python - <<'PY'
25
+ from pathlib import Path
26
+ import os
27
+ import tomllib
28
+
29
+ ref = os.environ["GITHUB_REF_NAME"]
30
+ tag_version = ref.removeprefix("v")
31
+ data = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
32
+ package_version = data["project"]["version"]
33
+ if package_version != tag_version:
34
+ raise SystemExit(
35
+ f"Tag version {tag_version!r} does not match project version {package_version!r}"
36
+ )
37
+ PY
38
+
39
+ - name: Install build tools
40
+ run: python -m pip install --upgrade build twine
41
+
42
+ - name: Run tests
43
+ run: PYTHONPATH=src python -m unittest discover tests
44
+
45
+ - name: Build distributions
46
+ run: python -m build
47
+
48
+ - name: Check distributions
49
+ run: python -m twine check dist/*
50
+
51
+ - name: Upload distributions
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: python-dist
55
+ path: dist/
56
+
57
+ publish:
58
+ name: Publish to PyPI
59
+ needs: build
60
+ runs-on: ubuntu-latest
61
+ permissions:
62
+ id-token: write
63
+
64
+ environment:
65
+ name: pypi
66
+ url: https://pypi.org/p/runlet
67
+
68
+ steps:
69
+ - name: Download distributions
70
+ uses: actions/download-artifact@v4
71
+ with:
72
+ name: python-dist
73
+ path: dist/
74
+
75
+ - name: Publish distributions
76
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .mypy_cache/
7
+ .pyright/
8
+ .venv/
9
+ dist/
10
+ build/
11
+ htmlcov/
12
+ .coverage
13
+
14
+ # Local planning and design drafts that should not be published.
15
+ .runlet-design/
runlet-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,73 @@
1
+ # Repository Instructions
2
+
3
+ These instructions apply to the entire repository.
4
+
5
+ ## Project Identity
6
+
7
+ - Project name: Runlet.
8
+ - Python package name: `runlet`.
9
+ - GitHub repository: `https://github.com/DMIAOCHEN/runlet`.
10
+ - License: MIT.
11
+ - Current status: pre-alpha package skeleton.
12
+
13
+ ## Product Direction
14
+
15
+ Runlet is a lightweight, provider-neutral Python agent runtime library. It is a
16
+ library, not a full application platform.
17
+
18
+ The core design goals are:
19
+
20
+ - Keep the runtime small and embeddable.
21
+ - Make context budgeting and compression mandatory before model calls.
22
+ - Provide flexible hooks around model calls, tool calls, state operations, and
23
+ context compression.
24
+ - Emit structured events for observability.
25
+ - Keep model providers, storage, tracing backends, and application frameworks
26
+ behind adapters.
27
+
28
+ ## Non-Goals
29
+
30
+ Do not turn the core package into:
31
+
32
+ - A web application framework.
33
+ - A hosted agent platform.
34
+ - A worker queue.
35
+ - A UI or trace viewer.
36
+ - A multi-tenant control plane.
37
+ - A graph workflow engine for the first release.
38
+
39
+ ## Design Drafts
40
+
41
+ Detailed internal design drafts, implementation planning notes, and private
42
+ brainstorming documents must go under:
43
+
44
+ ```text
45
+ .runlet-design/
46
+ ```
47
+
48
+ This directory is intentionally ignored by Git and must not be committed or
49
+ pushed to GitHub.
50
+
51
+ Public docs under `docs/` should stay high-level and suitable for open-source
52
+ readers. Do not put private planning notes, unfinished internal specs, or
53
+ conversation transcripts in public docs.
54
+
55
+ ## Development Practices
56
+
57
+ - Prefer simple Python modules and explicit protocols over framework-heavy
58
+ abstractions.
59
+ - Do not add provider SDK dependencies to core runtime modules.
60
+ - Use `apply_patch` for manual file edits.
61
+ - Keep generated caches such as `__pycache__/` out of commits.
62
+ - Current test command, when tests exist:
63
+
64
+ ```bash
65
+ PYTHONPATH=src python3 -m unittest discover tests
66
+ ```
67
+
68
+ ## Git Notes
69
+
70
+ The default branch is `main`.
71
+
72
+ If commands need to write Git metadata in this environment, they may require
73
+ escalated permissions because `.git` can appear read-only inside the sandbox.
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to Runlet will be documented here.
4
+
5
+ ## 0.1.0 - Unreleased
6
+
7
+ - Initialized the Python package skeleton.
8
+ - Added MIT license metadata.
9
+ - Added early project documentation and GitHub collaboration templates.
10
+
@@ -0,0 +1,15 @@
1
+ # Code of Conduct
2
+
3
+ Runlet aims to be a focused and respectful technical project.
4
+
5
+ Participants are expected to:
6
+
7
+ - Be direct, constructive, and specific.
8
+ - Debate technical tradeoffs without personal attacks.
9
+ - Respect maintainers' decisions about project scope.
10
+ - Avoid harassment, discrimination, or disruptive behavior.
11
+
12
+ Unacceptable behavior can be reported through the security or maintainer contact
13
+ channels listed by the project repository. Maintainers may remove comments,
14
+ close issues, or restrict participation when needed to protect the project.
15
+
@@ -0,0 +1,33 @@
1
+ # Contributing
2
+
3
+ Runlet is early-stage. Contributions should preserve the project direction:
4
+ small core, explicit extension points, strict context safety, and structured
5
+ observability.
6
+
7
+ ## Development
8
+
9
+ Use Python 3.10 or newer.
10
+
11
+ ```bash
12
+ python3 -m unittest discover tests
13
+ ```
14
+
15
+ ## Contribution Guidelines
16
+
17
+ - Keep runtime behavior provider-neutral.
18
+ - Prefer protocols and small data objects over framework-heavy abstractions.
19
+ - Do not add application-layer features such as web servers, task queues, UI, or
20
+ multi-tenant management to the core package.
21
+ - Add tests for runtime behavior once runtime modules exist.
22
+ - Document new extension points before exposing them as public API.
23
+
24
+ ## Pull Requests
25
+
26
+ Before opening a pull request, include:
27
+
28
+ - What changed and why.
29
+ - The runtime API or behavior impact.
30
+ - The observability impact, if any.
31
+ - The context-budgeting impact, if any.
32
+ - The test command you ran.
33
+
runlet-0.1.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Runlet contributors
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.
22
+
runlet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,256 @@
1
+ Metadata-Version: 2.4
2
+ Name: runlet
3
+ Version: 0.1.0
4
+ Summary: A tiny observable runtime for Python agents.
5
+ Project-URL: Homepage, https://github.com/DMIAOCHEN/runlet
6
+ Project-URL: Repository, https://github.com/DMIAOCHEN/runlet
7
+ Project-URL: Issues, https://github.com/DMIAOCHEN/runlet/issues
8
+ Author: Runlet contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,hooks,llm,observability,runtime
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Provides-Extra: openai
22
+ Requires-Dist: openai>=1.0.0; extra == 'openai'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Runlet
26
+
27
+ Runlet is a tiny observable runtime for Python agents.
28
+
29
+ The project is a library, not an application framework. Its core direction is a
30
+ provider-neutral, async-first agent runtime with strict context budgeting,
31
+ structured observability, and flexible hooks around model and tool execution.
32
+
33
+ ## Current Status
34
+
35
+ This repository now contains an MVP runtime skeleton with core contracts,
36
+ events, tools, hooks, context budgeting, streaming, provider adapters, and
37
+ in-memory state. The API is not stable yet.
38
+
39
+ ## Design Goals
40
+
41
+ - Keep the core runtime small and embeddable.
42
+ - Treat context budgeting and compression as mandatory runtime safety checks.
43
+ - Expose hooks before and after model calls, tool calls, state operations, and
44
+ context compression.
45
+ - Emit structured events for runs, steps, model calls, tool calls, context
46
+ changes, state changes, and failures.
47
+ - Stay provider-neutral: model SDKs integrate through adapters, not core
48
+ dependencies.
49
+
50
+ ## Non-Goals
51
+
52
+ Runlet core does not aim to provide:
53
+
54
+ - A web application framework.
55
+ - A hosted agent platform.
56
+ - A task queue or worker system.
57
+ - A UI or trace viewer.
58
+ - A multi-tenant control plane.
59
+ - A graph workflow engine in the first release.
60
+
61
+ ## Project Documents
62
+
63
+ - [Architecture](docs/architecture.md)
64
+ - [Design Principles](docs/design-principles.md)
65
+ - [Comparison](docs/comparison.md)
66
+ - [Roadmap](docs/roadmap.md)
67
+ - [Contributing](CONTRIBUTING.md)
68
+ - [Security](SECURITY.md)
69
+
70
+ ## Minimal Shape
71
+
72
+ ```python
73
+ from runlet import Agent, Runtime, tool
74
+
75
+
76
+ @tool
77
+ async def lookup(order_id: str) -> str:
78
+ return f"order {order_id}"
79
+
80
+
81
+ agent = Agent(
82
+ name="support",
83
+ instructions="Help users with orders.",
84
+ model=my_model_provider,
85
+ tools=(lookup,),
86
+ )
87
+
88
+ result = await Runtime().run(agent, "Where is order 123?")
89
+ ```
90
+
91
+ ## OpenAI Provider
92
+
93
+ Install the optional OpenAI dependency:
94
+
95
+ ```bash
96
+ pip install "runlet[openai]"
97
+ ```
98
+
99
+ Minimal example:
100
+
101
+ ```python
102
+ from runlet import Agent, Runtime
103
+ from runlet.providers import OpenAIResponsesProvider
104
+
105
+
106
+ provider = OpenAIResponsesProvider(model="gpt-5.5")
107
+
108
+ agent = Agent(
109
+ name="assistant",
110
+ instructions="Be helpful.",
111
+ model=provider,
112
+ )
113
+
114
+ result = await Runtime().run(agent, "Say hello in one sentence.")
115
+ ```
116
+
117
+ Custom base URL:
118
+
119
+ ```python
120
+ from runlet.providers import OpenAIResponsesProvider
121
+
122
+
123
+ provider = OpenAIResponsesProvider(
124
+ model="gpt-5.5",
125
+ base_url="https://your-endpoint.example/v1",
126
+ )
127
+ ```
128
+
129
+ Provider-specific request options:
130
+
131
+ ```python
132
+ from runlet.core import Message
133
+ from runlet.core.models import ModelRequest
134
+ from runlet.providers import OpenAIResponsesProvider
135
+
136
+
137
+ provider = OpenAIResponsesProvider(model="gpt-5.5")
138
+
139
+
140
+ request = ModelRequest(
141
+ messages=[Message.user("Summarize this briefly.")],
142
+ options={
143
+ "openai": {
144
+ "extra_body": {
145
+ "reasoning": {"effort": "medium"},
146
+ },
147
+ },
148
+ },
149
+ )
150
+
151
+ response = await provider.complete(request)
152
+ ```
153
+
154
+ Streaming text deltas:
155
+
156
+ ```python
157
+ from runlet import Agent, Runtime
158
+ from runlet.providers import OpenAIResponsesProvider
159
+
160
+
161
+ provider = OpenAIResponsesProvider(model="gpt-5.5")
162
+ agent = Agent(
163
+ name="assistant",
164
+ instructions="Be helpful.",
165
+ model=provider,
166
+ )
167
+
168
+ async for event in Runtime().stream(agent, "Explain recursion in one sentence."):
169
+ if event.type == "model.stream.delta":
170
+ print(event.payload["delta"], end="")
171
+ ```
172
+
173
+ Streaming with tool execution:
174
+
175
+ ```python
176
+ from runlet import Agent, Runtime, tool
177
+ from runlet.providers import OpenAIResponsesProvider
178
+
179
+
180
+ @tool
181
+ async def lookup_order(order_id: str) -> str:
182
+ return f"order {order_id} shipped"
183
+
184
+
185
+ provider = OpenAIResponsesProvider(model="gpt-5.5")
186
+ agent = Agent(
187
+ name="assistant",
188
+ instructions="Use tools when needed.",
189
+ model=provider,
190
+ tools=(lookup_order,),
191
+ )
192
+
193
+ async for event in Runtime().stream(agent, "Check order 123 and tell me the result."):
194
+ if event.type == "model.stream.delta":
195
+ print(event.payload["delta"], end="")
196
+ ```
197
+
198
+ When the provider emits a tool call during streaming, `Runtime.stream()` now
199
+ executes the tool, appends the tool result to the conversation, and continues
200
+ the next model round until the run completes.
201
+
202
+ Current scope of the provider:
203
+
204
+ - `complete()` supported
205
+ - `capabilities()` supported
206
+ - `stream()` supported
207
+ - text deltas supported
208
+ - streaming tool execution through `Runtime.stream()` supported
209
+ - `base_url` supported
210
+ - `options["openai"]["extra_body"]` supported
211
+ - provider-specific request options stay under `ModelRequest.options["openai"]`
212
+
213
+ Current streaming contract:
214
+
215
+ - providers can emit provider-neutral streaming step events internally
216
+ - `Runtime.stream()` handles multi-round tool execution loops
217
+ - OpenAI is the first provider implementation of this contract
218
+
219
+ ## Development
220
+
221
+ Run the current test suite:
222
+
223
+ ```bash
224
+ PYTHONPATH=src python3 -m unittest discover tests
225
+ ```
226
+
227
+ ## Releasing
228
+
229
+ Runlet publishes to PyPI from Git tags through GitHub Actions.
230
+
231
+ Release flow:
232
+
233
+ 1. Update `[project].version` in `pyproject.toml`
234
+ 2. Merge the release commit to `main`
235
+ 3. Create a version tag such as `v0.1.0`
236
+ 4. Push the tag to GitHub
237
+
238
+ The publish workflow will:
239
+
240
+ - verify the Git tag matches `pyproject.toml`
241
+ - run the test suite
242
+ - build `sdist` and `wheel`
243
+ - validate package metadata
244
+ - publish to PyPI through Trusted Publishing
245
+
246
+ Example:
247
+
248
+ ```bash
249
+ git tag v0.1.0
250
+ git push origin v0.1.0
251
+ ```
252
+
253
+ Repository setup requirement:
254
+
255
+ - configure PyPI Trusted Publishing for this GitHub repository and the
256
+ `.github/workflows/publish.yml` workflow