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.
- runlet-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
- runlet-0.1.0/.github/ISSUE_TEMPLATE/design_discussion.md +18 -0
- runlet-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- runlet-0.1.0/.github/pull_request_template.md +17 -0
- runlet-0.1.0/.github/workflows/ci.yml +28 -0
- runlet-0.1.0/.github/workflows/publish.yml +76 -0
- runlet-0.1.0/.gitignore +15 -0
- runlet-0.1.0/AGENTS.md +73 -0
- runlet-0.1.0/CHANGELOG.md +10 -0
- runlet-0.1.0/CODE_OF_CONDUCT.md +15 -0
- runlet-0.1.0/CONTRIBUTING.md +33 -0
- runlet-0.1.0/LICENSE +22 -0
- runlet-0.1.0/PKG-INFO +256 -0
- runlet-0.1.0/README.md +232 -0
- runlet-0.1.0/SECURITY.md +27 -0
- runlet-0.1.0/docs/architecture.md +62 -0
- runlet-0.1.0/docs/comparison.md +30 -0
- runlet-0.1.0/docs/design-principles.md +33 -0
- runlet-0.1.0/docs/roadmap.md +29 -0
- runlet-0.1.0/pyproject.toml +51 -0
- runlet-0.1.0/src/runlet/__init__.py +87 -0
- runlet-0.1.0/src/runlet/core/__init__.py +52 -0
- runlet-0.1.0/src/runlet/core/agent.py +18 -0
- runlet-0.1.0/src/runlet/core/errors.py +34 -0
- runlet-0.1.0/src/runlet/core/events.py +51 -0
- runlet-0.1.0/src/runlet/core/messages.py +47 -0
- runlet-0.1.0/src/runlet/core/models.py +130 -0
- runlet-0.1.0/src/runlet/core/runs.py +82 -0
- runlet-0.1.0/src/runlet/integrations/__init__.py +13 -0
- runlet-0.1.0/src/runlet/integrations/hooks.py +50 -0
- runlet-0.1.0/src/runlet/integrations/tools.py +77 -0
- runlet-0.1.0/src/runlet/providers/__init__.py +5 -0
- runlet-0.1.0/src/runlet/providers/openai.py +156 -0
- runlet-0.1.0/src/runlet/py.typed +1 -0
- runlet-0.1.0/src/runlet/runtime/__init__.py +20 -0
- runlet-0.1.0/src/runlet/runtime/context.py +48 -0
- runlet-0.1.0/src/runlet/runtime/engine.py +255 -0
- runlet-0.1.0/src/runlet/runtime/policies.py +23 -0
- runlet-0.1.0/src/runlet/runtime/state.py +29 -0
- runlet-0.1.0/src/runlet/testing/__init__.py +6 -0
- runlet-0.1.0/src/runlet/testing/fakes.py +56 -0
- runlet-0.1.0/tests/test_context.py +25 -0
- runlet-0.1.0/tests/test_core.py +74 -0
- runlet-0.1.0/tests/test_events.py +26 -0
- runlet-0.1.0/tests/test_hooks.py +39 -0
- runlet-0.1.0/tests/test_models.py +43 -0
- runlet-0.1.0/tests/test_openai_provider.py +212 -0
- runlet-0.1.0/tests/test_package_layout.py +14 -0
- runlet-0.1.0/tests/test_public_api.py +23 -0
- runlet-0.1.0/tests/test_runtime_basic.py +25 -0
- runlet-0.1.0/tests/test_runtime_streaming.py +22 -0
- runlet-0.1.0/tests/test_runtime_streaming_tools.py +92 -0
- runlet-0.1.0/tests/test_runtime_tools.py +37 -0
- runlet-0.1.0/tests/test_state.py +24 -0
- 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
|
runlet-0.1.0/.gitignore
ADDED
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,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
|