rosa-llm
OpenAI through ChatGPT OAuth and local Ollama, behind one Python interface.
Use it as a standalone client or supply ChatRosaLLM to LangChain and ROSA.
The package handles model communication; your application executes tools and
owns its agent logic, experiment design, and outcome checks.
v0.1.0 · Python ≥3.11 · Apache-2.0
Install · Provider setup · Python API · LangChain and ROSA · Docker · Configuration · Troubleshooting
| Use case | What you need |
|---|---|
| Standalone client | Python and a configured provider; ROS and LangChain are optional |
| OpenAI | Your own ChatGPT account with eligible model access and plan-use permission; no OpenAI API key |
| Ollama | A reachable server and an already installed model |
| LangChain / ROSA | The langchain extra and your existing agent/ROS environment |
Install
In an existing uv project
For the base client:
uv add "rosa-llm==0.1.0"
For LangChain or ROSA, use this dependency instead:
uv add "rosa-llm[langchain]==0.1.0"
These commands install the PyPI release.
uv add updates the consuming project's dependencies and lockfile; ==0.1.0
selects this exact version. No PyPI or GitHub sign-in is required to install it.
If your project already declares this dependency, use its uv sync --locked;
a separate package clone is unnecessary.
Version 0.1.0 renumbers the initial release with the same runtime code previously published as 0.2.0. That earlier upload remains available. Use the explicit pin above: an unpinned install can select 0.2.0 because it sorts higher.
Python compatibility: the base package and adapter require ≥3.11 and have been tested on 3.11 and 3.12 under Linux/WSL x86_64. This checkout and Docker use 3.12. Use Python 3.12 for the installed ROS 2 Jazzy bindings; the package does not install ROS. See verified versions and limits.
Pinning a research dependency or keeping a Python ≥3.9 project
To install directly from Git instead of PyPI, use the release tag:
uv add "rosa-llm[langchain] @ git+https://github.com/Lelevinson/rosa-llm-package.git@v0.1.0"
A tag installation records its resolved commit in uv.lock. Use the full commit
SHA instead of the tag in the Git URL when an immutable source reference is required.
uv checks the consumer's declared Python range, not just its active interpreter. For a project that retains ≥3.9 support, a conditional dependency can omit this adapter on Python 3.9/3.10:
uv add --marker "python_version >= '3.11'" \
"rosa-llm[langchain]==0.1.0"
--marker makes the dependency conditional. Older interpreters will not receive
the adapter. Existing ROS bindings and dependency groups may require a newer
Python version independently. Lowering this package's minimum alone does not
resolve every consumer's compatibility constraints.
Run the CLI from a checkout
With Git, Python 3.12, and uv available, run in your Linux or WSL terminal:
git clone https://github.com/Lelevinson/rosa-llm-package.git
cd rosa-llm-package
uv sync --locked
uv run rosa-llm init
git clone downloads the project; cd enters it. uv sync --locked installs the
locked environment in .venv; uv run executes a command there. init creates
.env and refuses to overwrite it. Skip init if you already have configuration.
See uv's sync behavior.
Provider setup
Choose a provider below. YOUR_OLLAMA_MODEL and YOUR_OPENAI_MODEL are
placeholders: replace them with names returned by the relevant catalog command.
Ollama
1. Configure the server address in your local .env:
LLM_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
In WSL, a Windows-hosted server may need the Windows host address instead. Use the address reachable from your own machine; the client does not switch endpoints, start servers, or download models.
2. Discover a model and make a request:
uv run rosa-llm models --provider ollama --json
uv run rosa-llm ask "Say hello" --provider ollama --model YOUR_OLLAMA_MODEL --json
Save that model as OLLAMA_MODEL in .env to avoid repeating --model.
Tool use requires a tool-capable model.
OpenAI — Sign in with ChatGPT
1. Authorize your own account:
uv run rosa-llm login --provider openai
uv run rosa-llm status --provider openai --json
Login opens a browser and listens on 127.0.0.1:1455/auth/callback.
Identity login and plan-use permission are separate; inference needs both.
status reads local state and does not confirm current remote access.
2. Discover a model, then request it explicitly:
ROSA_LLM_REQUIRE_EXPLICIT_MODEL=false uv run rosa-llm models --provider openai --json
uv run rosa-llm ask "Say hello" --provider openai --model YOUR_OPENAI_MODEL --json
The assignment before models disables the explicit-model guard for that command
only, allowing discovery before a model is configured. It does not change .env.
--provider and --model override configuration for one command.
3. Save your selection in .env:
LLM_PROVIDER=openai
OPENAI_MODEL=YOUR_OPENAI_MODEL
ROSA_LLM_REQUIRE_EXPLICIT_MODEL=true
Credentials are saved outside the repository. Each teammate signs in separately; GitHub access does not provide model access. An OpenAI API key is not used here.
Browser forwarding, profiles, consent, and logout
- No browser window? Run
uv run rosa-llm login --no-browserand open the printed authorization URL on the browser host while login remains running. Keep the URL private; do not paste callback URLs into chat. - WSL: Windows-to-WSL localhost forwarding must reach the listener. Keep the
callback host as
127.0.0.1; do not replace it withlocalhostor expose it publicly.--port 0selects a free loopback port. - Existing SSH access: on the browser host, run
ssh -N -L 1455:127.0.0.1:1455 user@your-linux-host, then run login on that Linux host with--no-browser --port 1455.-Nruns only forwarding;-Lforwards the local port to the remote loopback listener. SSH setup is external. - Separate accounts/workspaces: use
--profile labon login and subsequent commands, or setROSA_LLM_PROFILE=lab. Labels accept letters, digits,_, and-. Returning logins reuse the registration and verify its subject. - Missing plan permission:
uv run rosa-llm login --consentrequests consent again. A new identity-only registration retains inference-disabled state; failed login does not replace an existing valid session. - Sign out:
uv run rosa-llm logout --jsonattempts remote revocation and clears the selected profile's tokens, retaining its registration and host ID. If revocation cannot be confirmed, disconnect the app in ChatGPT Settings.
Python API
The base API needs no ROS, LangChain, database, or agent runtime:
from rosa_llm import create_client
with create_client() as client:
response = client.generate("Explain a ROS 2 node briefly.")
print(response.text)
print(response.model, response.usage)
create_client() loads configuration from the calling directory. For explicit
settings, pass Config(...), or use create_client(env_file="path/to/.env").
Keep client use inside with so its HTTP resources close afterward.
| Interface | Contract |
|---|---|
client.generate(prompt) |
Returns a validated completed Response; partial output is not returned as success |
client.generate(messages) |
Uses explicit history; retain response.message to preserve native reasoning and tool-call items |
client.stream(prompt) |
Yields text events and a final completed response; exhaust or close the iterator and handle LLMError |
Tool(...) / response.tool_calls |
Declares tools and receives requests; your code validates arguments and executes them |
create_client(observer=callback) |
Captures request records; the application owns thread-safe, durable storage and task scoring |
Plain text history is portable across providers; opaque provider history is not. OpenAI maps system instructions to developer messages. Ollama accepts system messages and rejects developer messages. Tool arguments are complete only after provider completion; do not execute partial streamed arguments.
Recipes: chat/history · native tool loop · request recording and timing.
LangChain and ROSA
Install with [langchain] as shown above. In this checkout, enable the extra with
uv sync --locked --extra langchain; it pins langchain-core==0.3.86.
from rosa_llm import create_client
from rosa_llm.langchain import ChatRosaLLM
with create_client() as client:
model = ChatRosaLLM(client=client)
print(model.invoke("Say hello").content)
Use ordinary LangChain tools through model.bind_tools(...) or an agent's normal
model interface. LangChain/your application executes tools; this adapter does not.
Keep the client open until all agent calls finish.
Pass the same adapter to an existing ROSA application
Install ROSA separately and source your ROS environment first. The package's Docker image does not supply ROS. With those dependencies available:
from rosa import ROSA
from rosa_llm import create_client
from rosa_llm.langchain import ChatRosaLLM
with create_client() as client:
model = ChatRosaLLM(client=client)
agent = ROSA(ros_version=2, llm=model, streaming=False)
print(agent.invoke("List the current ROS 2 nodes."))
The model adapter is infrastructure. Your research code still owns policies, tool permissions, observations, experimental conditions, and outcome validation.
| Capability | OpenAI ChatGPT OAuth | Ollama |
|---|---|---|
| Text/history and streamed text | Supported | Supported |
| JSON function tools | Supported; native API wraps tools in namespaces | Supported; JSON-object arguments |
| Custom text tools | Native API only | Unsupported |
| LangChain tools | Text/function-tool contract | Text/function-tool contract |
| Per-call options | tool_choice (auto, none, required), parallel_tool_calls |
options, think, format, keep_alive |
| Async | LangChain worker-thread interface; base client uses synchronous HTTP | Same |
Unsupported options fail explicitly. Do not assume temperature/seed controls,
strict schemas, hosted tools, images/files, or arbitrary OpenAI parameters are
portable across providers. There are no constructor-level decoding defaults on
ChatRosaLLM in v0.1.0; supplying per-call options and retaining them through an
agent's tool-binding step is the caller's responsibility.
See integration examples, custom LangChain tools, and the compatibility report for exact supported scope.
Docker
Status: Dockerfiles/Compose configuration are provided. Image build, runtime, and credential persistence have not been live-verified in this environment. See verification limits.
The image is a standalone Python 3.12 client, not a complete ROS/Jazzy environment.
For an existing ROS container, install the Git dependency into that application's
environment. This image defaults to the base client; build with
--build-arg INSTALL_LANGCHAIN=true to include the optional adapter.
Create a local .env from .env.example if one does not already exist, then:
docker compose build
docker compose run --rm rosa-llm models --provider ollama --json
docker compose run --rm rosa-llm ask "Say hello" --provider ollama --model YOUR_OLLAMA_MODEL --json
build creates the image. run --rm removes the command container when it exits;
the named credential volume persists. Compose loads .env.
| Setting | Container behavior |
|---|---|
| Ollama endpoint | DOCKER_OLLAMA_BASE_URL, default http://host.docker.internal:11434; server must listen on a reachable interface |
| Credential directory | /home/app/.config/rosa-llm, persisted in the auth named volume |
| Runtime user | Non-root UID 10001; bind-mounted credential directories must be owned by that UID and mode 700 |
OAuth login in Docker
On native Linux, or Docker Desktop with host networking enabled:
docker compose -f compose.yaml -f compose.login.yaml run --rm rosa-llm login --no-browser
docker compose run --rm -e ROSA_LLM_REQUIRE_EXPLICIT_MODEL=false rosa-llm models --provider openai --json
docker compose run --rm rosa-llm ask "Say hello" --provider openai --model YOUR_OPENAI_MODEL --json
-f selects Compose files; the later file overrides the earlier one. -e sets
an environment variable inside that command's container. Open the printed URL in the browser on that host while login waits. The listener remains
on loopback. Bridge networking and publishing a port do not make a listener bound
to the container's 127.0.0.1 reachable from the host. The project does not enable
host networking or change host firewalls/Ollama bindings for you.
If host networking is unavailable, use an existing SSH tunnel, or complete WSL
login and securely move your own credential/host-identity directory into your
private volume with the correct ownership. Move the runtime identity together;
do not operate concurrent independent copies. Never share credential volumes
between teammates. Use the same Compose project/volume across commands, and avoid
docker compose down -v unless credential deletion is intentional (-v deletes
named volumes). Native Windows Python is outside this release's tested scope.
Configuration
Edit the .env in the directory from which your application runs. No tokens or
API keys belong in this file.
| Variable | Default | Purpose |
|---|---|---|
LLM_PROVIDER |
ollama |
ollama or openai |
OLLAMA_MODEL |
qwen3:8b |
Installed model name |
OLLAMA_BASE_URL |
http://localhost:11434 |
Endpoint reachable from this process |
OPENAI_MODEL |
Empty | Account-visible model name; empty otherwise selects the first visible catalog entry on each request |
ROSA_LLM_REQUIRE_EXPLICIT_MODEL |
false |
Set true for controlled OpenAI runs to reject missing model selection |
ROSA_LLM_PROFILE |
default |
Saved OAuth registration label |
ROSA_LLM_AUTH_DIR |
User configuration directory | Credential/host storage outside the repository; empty uses the default |
ROSA_LLM_TIMEOUT |
120 |
HTTP phase timeout in seconds, not a total trial deadline |
Precedence, highest first: process environment → local .env → user
config.env → defaults. The user directory is $XDG_CONFIG_HOME/rosa-llm, normally
~/.config/rosa-llm. uv run rosa-llm init --user creates its config.env.
The loader does not change process environment or expand ${...} in dotenv values.
For reproducible runs, select a named model rather than relying on catalog order.
CLI reference
All options follow the subcommand; for example, uv run rosa-llm ask --help.
| Command | What it does |
|---|---|
init |
Creates configuration without overwriting an existing file |
login / logout |
Signs in / clears the selected profile's tokens, attempting remote revocation |
status --json |
Reads local authentication state; does not contact OpenAI |
models --json |
Queries the selected provider's model catalog |
ask "prompt" --json |
Performs real inference; JSON includes provider/model, text, tool calls, usage, and available metadata |
ask "prompt" --stream |
Prints text deltas; incompatible with --json |
test --json |
Makes one real request and checks an exact short marker |
test --tool --json |
Checks one harmless echo tool round trip, arguments, and final marker; at most two model requests |
Common overrides: --provider, --model, --profile, --env-file PATH.
Diagnostics go to stderr. JSON-mode failures emit an error object and exit 1.
Inference never opens a login prompt or automatically retries/falls back.
Partial streaming output is not proof of success; check the exit status.
Credentials and transport
- Default storage:
~/.config/rosa-llm/credentials.jsonandhost.json. Profiles belong to this package; it does not reuse Codex credentials. Files are plaintext protected by OS permissions, not encrypted. - Storage directories use mode 700; credential, host, temporary, and lock files use mode 600. Refreshes atomically rotate tokens under a Linux process lock. Local filesystems are required; NFS/distributed locking is outside scope.
- Expired tokens renew automatically when possible. Revoked sessions need login again; temporary network failures preserve credentials. Keep credentials and authorization URLs private. Never put GitHub/model tokens in Git URLs or logs.
- Redirects and environment proxy variables are disabled on internally created HTTP clients; TLS verification stays enabled. Do not enable HTTP wire/debug logging around OAuth, because it can expose secrets.
Troubleshooting
| Symptom | First check |
|---|---|
| Ollama connection refused | Verify the server, installed model, and endpoint from this WSL/container; localhost may address the wrong machine |
| Browser callback fails | Keep login running; check WSL forwarding or Docker host networking and port conflicts |
| Logged in, inference disabled | Check plan eligibility/permission; use login --consent to request permission again |
| OpenAI model unavailable | Refresh the catalog using the command in OpenAI setup; select a listed model |
| Explicit-model error during discovery | Prefix the catalog command with ROSA_LLM_REQUIRE_EXPLICIT_MODEL=false; keep inference guard enabled afterward |
| Usage limit or provider unavailable | Review ChatGPT Usage; stop or defer requests rather than bypassing limits |
| Credential permission error | Check user ownership, file mode 600, directory mode 700, and Docker UID 10001 |
| Stream ends with an error | Record failure even if text was already printed; generate() does not return that partial result as completed |
| Unsupported option/tool/message | Check the compatibility contract; capabilities differ by provider |
Development and reference
uv sync --locked --extra langchain
uv run --locked pytest -q
uv run --locked ruff check .
uv run --locked ruff format --check .
uv build
pytest -q runs automated tests with concise output; it does not authorize accounts
or run live model requests. Third-party pytest plugin auto-loading is disabled.
Optional ROSA executor checks also need the integration group and sourced Jazzy;
see the integration guide.
ruff check checks code; format --check checks formatting without editing.
uv build creates a wheel and source distribution under dist/.
| Reference | Contents |
|---|---|
| LangChain / ROSA | Optional installation, agent examples, ROS environment requirements |
| Compatibility | Tool/message contracts, supported interfaces, provider restrictions |
| Experiment recording | Native records, timing definitions, provenance, runner responsibilities |
| Python support | Tested versions, wheel checks, dependency-resolution boundaries |
| Protocol | Official OAuth/protocol sources |
| Publishing | Maintainer setup, dry runs, and PyPI Trusted Publishing |
| Hardening / validation | Dated evidence and remaining manual checks |
Source layout
| Module | Responsibility |
|---|---|
client.py, types.py |
Shared client API and message/tool/response types |
providers.py, http.py |
Provider wire formats, stream parsing, safe error classification |
auth.py, storage.py |
OAuth, token validation/refresh, protected credential storage |
config.py, cli.py |
Configuration precedence and command-line interface |
langchain.py, provenance.py |
Optional model adapter and package/source identity |
Runtime dependencies are httpx, python-dotenv, and PyJWT[crypto].
Development uses pytest and Ruff; uv_build builds the package.
Metadata
Release files for rosa-llm 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| rosa_llm-0.1.0.tar.gz | 47.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rosa_llm-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.8 kB
Release files / rosa_llm-0.1.0.tar.gz
| Download URL | rosa_llm-0.1.0.tar.gz |
|---|---|
| Size | 47.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34a24283fc8c0500bcc41c997bd462749fefdb7ca244f1fbfba95b90783640a5
|
|
BLAKE2b-256 checksum How to use checksums |
05ec8e6353da7b8d153a71cf1afb391a36d60de7b3b20b4971856e4264fd486b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / rosa_llm-0.1.0-py3-none-any.whl
| Download URL | rosa_llm-0.1.0-py3-none-any.whl |
|---|---|
| Size | 46.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a43f50861310c2bd87af05552a7921d2f493ca29c292b604db5c3dd598f0f06
|
|
BLAKE2b-256 checksum How to use checksums |
e30977f8b56bafc61986332ed8b2ce6b9683edc967a9f9d3854688831deca211
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for rosa-llm 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for rosa_llm-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.