rosa-llm 0.2.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.
- rosa_llm-0.2.0/LICENSE +202 -0
- rosa_llm-0.2.0/PKG-INFO +349 -0
- rosa_llm-0.2.0/README.md +332 -0
- rosa_llm-0.2.0/pyproject.toml +56 -0
- rosa_llm-0.2.0/pyproject.toml.orig +53 -0
- rosa_llm-0.2.0/src/rosa_llm/__init__.py +36 -0
- rosa_llm-0.2.0/src/rosa_llm/__main__.py +3 -0
- rosa_llm-0.2.0/src/rosa_llm/auth.py +497 -0
- rosa_llm-0.2.0/src/rosa_llm/cli.py +273 -0
- rosa_llm-0.2.0/src/rosa_llm/client.py +252 -0
- rosa_llm-0.2.0/src/rosa_llm/config.py +109 -0
- rosa_llm-0.2.0/src/rosa_llm/errors.py +61 -0
- rosa_llm-0.2.0/src/rosa_llm/http.py +167 -0
- rosa_llm-0.2.0/src/rosa_llm/langchain.py +453 -0
- rosa_llm-0.2.0/src/rosa_llm/provenance.py +62 -0
- rosa_llm-0.2.0/src/rosa_llm/providers.py +494 -0
- rosa_llm-0.2.0/src/rosa_llm/storage.py +112 -0
- rosa_llm-0.2.0/src/rosa_llm/types.py +117 -0
rosa_llm-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
rosa_llm-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rosa-llm
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Standalone Ollama and ChatGPT OAuth clients with a shared Python API and CLI
|
|
5
|
+
Author: levii831
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
|
9
|
+
Requires-Dist: pyjwt[crypto]>=2.15.1
|
|
10
|
+
Requires-Dist: python-dotenv>=1.2.4
|
|
11
|
+
Requires-Dist: langchain-core==0.3.86 ; extra == 'langchain'
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Project-URL: Repository, https://github.com/Lelevinson/rosa-llm-package
|
|
14
|
+
Project-URL: Issues, https://github.com/Lelevinson/rosa-llm-package/issues
|
|
15
|
+
Provides-Extra: langchain
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# rosa-llm
|
|
19
|
+
|
|
20
|
+
Licensed under [Apache-2.0](LICENSE).
|
|
21
|
+
|
|
22
|
+
Version 0.2.0 hardens history replay, diagnostics and request provenance. See the
|
|
23
|
+
[hardening results](docs/hardening-report.md) and the
|
|
24
|
+
[experiment recording contract](docs/experiment-recording.md) for the current
|
|
25
|
+
interfaces, corrected behaviors and remaining provider/environment limits.
|
|
26
|
+
|
|
27
|
+
A standalone Python 3.11+ package for Ollama and official Sign in with ChatGPT
|
|
28
|
+
OAuth. No ROS, ROSA, LangChain, database, API key, or agent runtime is required.
|
|
29
|
+
ChatGPT-plan inference requires an eligible account and an explicit permission
|
|
30
|
+
grant; a successful identity login alone is insufficient.
|
|
31
|
+
|
|
32
|
+
An optional [LangChain adapter and ROSA integration guide](docs/langchain-integration.md)
|
|
33
|
+
is available. The [general compatibility report](docs/langchain-compatibility.md)
|
|
34
|
+
covers supported custom tools, provider differences, test evidence and limits.
|
|
35
|
+
ROSA 1.0.10 has also been tested without modifying its source.
|
|
36
|
+
|
|
37
|
+
The base client and optional LangChain adapter support Python 3.11 and 3.12.
|
|
38
|
+
The checkout keeps `.python-version` at 3.12 for ROS 2 Jazzy; the Docker image
|
|
39
|
+
also stays on 3.12. Standalone installations can use Python 3.11. See the
|
|
40
|
+
[Python compatibility and verification report](docs/python-compatibility.md)
|
|
41
|
+
for the supported scope and the separate ROSA Research dependency-resolution boundary.
|
|
42
|
+
|
|
43
|
+
## Install in WSL Ubuntu
|
|
44
|
+
|
|
45
|
+
With Python 3.12 and [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
46
|
+
available, open a WSL terminal. The intended GitHub repository is public;
|
|
47
|
+
HTTPS cloning does not require GitHub sign-in once publication is approved:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/Lelevinson/rosa-llm-package.git
|
|
51
|
+
cd rosa-llm-package
|
|
52
|
+
uv sync --locked
|
|
53
|
+
uv run rosa-llm init
|
|
54
|
+
uv run rosa-llm status --json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`uv sync` installs this project and its locked dependencies into `.venv`;
|
|
58
|
+
`--locked` refuses to change `uv.lock`. `uv run` runs the following command in
|
|
59
|
+
that environment. `init` creates `.env` and refuses to overwrite existing settings.
|
|
60
|
+
`git clone` downloads the repository into a new local directory; `cd` enters
|
|
61
|
+
that directory. For an existing checkout, start with `cd` and skip cloning.
|
|
62
|
+
No global Python installation is modified. Public repository reads and model
|
|
63
|
+
access are separate: each user supplies their own ChatGPT OAuth session or a
|
|
64
|
+
reachable Ollama server. GitHub authentication is needed for repository writes.
|
|
65
|
+
Never put a GitHub token in a Git URL, `.env`, `pyproject.toml` or `uv.lock`.
|
|
66
|
+
|
|
67
|
+
## Configure and switch providers
|
|
68
|
+
|
|
69
|
+
Edit `.env` in the directory from which you run the program:
|
|
70
|
+
|
|
71
|
+
```dotenv
|
|
72
|
+
LLM_PROVIDER=ollama
|
|
73
|
+
OLLAMA_MODEL=qwen3:8b
|
|
74
|
+
OLLAMA_BASE_URL=http://localhost:11434
|
|
75
|
+
OPENAI_MODEL=
|
|
76
|
+
ROSA_LLM_AUTH_DIR=
|
|
77
|
+
ROSA_LLM_PROFILE=default
|
|
78
|
+
ROSA_LLM_TIMEOUT=120
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For Ollama, the endpoint must already be reachable and the selected model must
|
|
82
|
+
already be installed. Use your actual model name from `rosa-llm models`.
|
|
83
|
+
For OpenAI, set `LLM_PROVIDER=openai`, then log in as described below.
|
|
84
|
+
Empty `OPENAI_MODEL` selects the first visible model in the account's ordered
|
|
85
|
+
catalog on each request. An explicit name must occur in that catalog.
|
|
86
|
+
|
|
87
|
+
Precedence, highest first: process environment, local `.env`, per-user
|
|
88
|
+
`$XDG_CONFIG_HOME/rosa-llm/config.env` (normally `~/.config/rosa-llm/config.env`),
|
|
89
|
+
then defaults. `uv run rosa-llm init --user` creates the per-user file.
|
|
90
|
+
The loader does not modify process environment or expand `${...}` in dotenv values.
|
|
91
|
+
An empty `ROSA_LLM_AUTH_DIR` uses the default user directory. Tokens never go in `.env`.
|
|
92
|
+
|
|
93
|
+
## Sign in with ChatGPT
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
uv run rosa-llm login
|
|
97
|
+
uv run rosa-llm status --provider openai --json
|
|
98
|
+
uv run rosa-llm models --provider openai --json
|
|
99
|
+
uv run rosa-llm ask "Explain ROS 2 in one sentence." --provider openai --json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`--provider` overrides the configured provider for that command. Login always
|
|
103
|
+
authenticates OpenAI, even while `.env` selects Ollama. Every team member signs
|
|
104
|
+
in using their own account; the program never requests a ChatGPT password.
|
|
105
|
+
It opens the system browser and listens only at `127.0.0.1:1455/auth/callback`.
|
|
106
|
+
`--port 0` selects a free loopback port. Each attempt uses the exact callback
|
|
107
|
+
URI in both authorization and code exchange.
|
|
108
|
+
|
|
109
|
+
In WSL, the browser can run on Windows. If the browser does not open:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv run rosa-llm login --no-browser
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Open the printed authorization URL in your Windows browser while the command
|
|
116
|
+
remains running. `--no-browser` disables browser launching. Keep the URL private;
|
|
117
|
+
printed URLs omit retained identity-token hints. WSL localhost forwarding must
|
|
118
|
+
reach the listener in Ubuntu. This is an environment requirement, not guaranteed
|
|
119
|
+
by the Python package. Do not change the callback host to `localhost`, paste a
|
|
120
|
+
callback URL into chat, or expose the listener publicly.
|
|
121
|
+
|
|
122
|
+
If forwarding fails, use an approved local SSH tunnel: on the browser's host,
|
|
123
|
+
run `ssh -N -L 1455:127.0.0.1:1455 user@your-wsl-or-linux-host`, then run login
|
|
124
|
+
on that Linux host with `--no-browser --port 1455`. `ssh -N` runs only forwarding;
|
|
125
|
+
`-L` maps the browser host's local port to the remote loopback listener. This
|
|
126
|
+
requires your existing SSH access; the package does not install or configure SSH.
|
|
127
|
+
|
|
128
|
+
Use `--profile lab` on login and subsequent commands to keep another registration
|
|
129
|
+
separate, or set `ROSA_LLM_PROFILE=lab`. Labels use letters, digits, `_`, and `-`.
|
|
130
|
+
To add a different account/workspace, choose a new label. Returning logins reuse
|
|
131
|
+
that profile's client ID and verify its subject. `status` shows the active label
|
|
132
|
+
without tokens and does not contact OpenAI or assert current remote eligibility.
|
|
133
|
+
|
|
134
|
+
If identity login succeeds without plan permission, a new identity registration
|
|
135
|
+
is retained with inference disabled. A failed login never replaces an existing
|
|
136
|
+
valid session. To explicitly ask for permission again:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
uv run rosa-llm login --consent
|
|
140
|
+
uv run rosa-llm logout --json
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`--consent` requests the consent screen again; ordinary returning logins do not.
|
|
144
|
+
`logout` attempts remote revocation, clears the selected profile's tokens, and
|
|
145
|
+
retains its registration and host identity. If remote revocation cannot be
|
|
146
|
+
confirmed, it reports that fact; disconnect the app in ChatGPT Settings.
|
|
147
|
+
|
|
148
|
+
## CLI and live smoke checks
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
uv run rosa-llm models --json
|
|
152
|
+
uv run rosa-llm ask "Say hello" --json
|
|
153
|
+
uv run rosa-llm ask "Explain a ROS 2 node briefly" --stream
|
|
154
|
+
uv run rosa-llm test --json
|
|
155
|
+
uv run rosa-llm test --tool --json
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`models` lists available models. `ask` performs real inference. `--json` emits
|
|
159
|
+
one JSON document on stdout, with provider, model, response, requested tools,
|
|
160
|
+
usage and available metadata. Diagnostics go to stderr; failures exit with code 1
|
|
161
|
+
and emit an `error` object. No inference command opens OAuth or prompts for input.
|
|
162
|
+
`--stream` prints text as it arrives and cannot be combined with `--json`.
|
|
163
|
+
Partial streamed text is not proof of completion: check the process exit code.
|
|
164
|
+
|
|
165
|
+
`test` makes one real request and checks an exact short marker. `--tool` instead
|
|
166
|
+
allows one harmless echo call and one follow-up request, validates the requested
|
|
167
|
+
name and arguments, and checks the final marker. Models that decline the call
|
|
168
|
+
fail the smoke check. Neither command downloads models or starts an agent.
|
|
169
|
+
`--model NAME` overrides the selected provider's model for one command.
|
|
170
|
+
`--env-file PATH` selects another local dotenv file. Options follow the command.
|
|
171
|
+
Use `uv run rosa-llm ask --help` for command syntax.
|
|
172
|
+
|
|
173
|
+
## Python API and another project
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from rosa_llm import Message, Tool, create_client
|
|
177
|
+
|
|
178
|
+
with create_client() as client:
|
|
179
|
+
response = client.generate("Explain what ROS 2 is.")
|
|
180
|
+
print(response.text)
|
|
181
|
+
print(response.tool_calls, response.model, response.usage)
|
|
182
|
+
|
|
183
|
+
history = [Message("user", "What is a node?")]
|
|
184
|
+
first = client.generate(history)
|
|
185
|
+
history += [first.message, Message("user", "Give one example.")]
|
|
186
|
+
print(client.generate(history).text)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
History is explicit; the client does not mutate it or retain a hidden session.
|
|
190
|
+
Keep `response.message` so provider-specific reasoning and tool-call data survive
|
|
191
|
+
the next request. Plain user/assistant text can be shared across providers;
|
|
192
|
+
opaque provider output cannot. System instructions map to developer messages on
|
|
193
|
+
the OpenAI OAuth route. Ollama supports system messages and rejects developer messages.
|
|
194
|
+
|
|
195
|
+
`client.stream(prompt)` yields `StreamEvent` objects: `text` contains deltas;
|
|
196
|
+
`completed` contains the final normalized `response`. Consume through completion
|
|
197
|
+
and handle `LLMError` exceptions. A completed empty response without tools is rejected.
|
|
198
|
+
Only the final response has complete tool calls; partial arguments are not executed.
|
|
199
|
+
|
|
200
|
+
`Tool(name, description, parameters)` declares a JSON function. OpenAI wraps it
|
|
201
|
+
in a namespace (default `local`); `Tool(..., kind="custom", format={"type":"text"})`
|
|
202
|
+
declares a custom text tool. Ollama rejects custom tools and explicit namespaces.
|
|
203
|
+
The caller must validate and execute requested tools, then append a `Message`
|
|
204
|
+
with role `tool`, `tool_call_id`, and `tool_name`; custom outputs also set
|
|
205
|
+
`tool_kind="custom"`. See [examples/tool_call.py](examples/tool_call.py) and
|
|
206
|
+
[examples/chat.py](examples/chat.py). Run examples with `uv run python examples/chat.py`.
|
|
207
|
+
|
|
208
|
+
From another uv project whose declared Python range is compatible with >=3.11:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
uv add "rosa-llm @ git+https://github.com/Lelevinson/rosa-llm-package.git@v0.2.0"
|
|
212
|
+
# Include the optional LangChain adapter when needed:
|
|
213
|
+
uv add "rosa-llm[langchain] @ git+https://github.com/Lelevinson/rosa-llm-package.git@v0.2.0"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`uv add` records the package as a dependency of the current project. uv checks
|
|
217
|
+
that project's declared Python range as well as the selected interpreter. A
|
|
218
|
+
consumer declaring >=3.9 still needs a compatible range or dependency marker;
|
|
219
|
+
this package change does not perform that consumer-side integration. Its local
|
|
220
|
+
`.env` is read from the calling directory. Alternatively pass `Config(...)` to
|
|
221
|
+
`create_client(config)` or pass `env_file="/path/to/.env"`.
|
|
222
|
+
These Git installation commands require the approved `v0.2.0` tag to exist on
|
|
223
|
+
GitHub. `@v0.2.0` selects that version reference; uv records its resolved commit
|
|
224
|
+
in the consumer lockfile. A consumer can instead pin the full commit SHA for an
|
|
225
|
+
immutable source reference. `uv add --editable /path/to/rosa-llm-package` remains
|
|
226
|
+
available for local package development, but shared research dependencies should
|
|
227
|
+
use the Git reference. Public HTTPS installation does not require a GitHub
|
|
228
|
+
token. Model credentials remain local to each user and are never shared.
|
|
229
|
+
|
|
230
|
+
## Docker
|
|
231
|
+
|
|
232
|
+
The image uses Python 3.12, uv, and a non-root user (UID 10001). A private named
|
|
233
|
+
volume holds credentials and host identity across disposable CLI containers.
|
|
234
|
+
Create `.env` using the WSL commands above, or copy `.env.example` to `.env`
|
|
235
|
+
(`cp` copies a file). For a Docker-only installation, copying needs no Python.
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
docker compose build
|
|
239
|
+
docker compose run --rm rosa-llm status --json
|
|
240
|
+
docker compose run --rm rosa-llm ask "Say hello" --json
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
`docker compose build` builds the image; `run --rm` runs one command and removes
|
|
244
|
+
its container afterward, preserving the named volume. Compose loads `.env`.
|
|
245
|
+
`DOCKER_OLLAMA_BASE_URL` overrides its Docker endpoint; the default is
|
|
246
|
+
`http://host.docker.internal:11434`. On native Linux this name maps to the host
|
|
247
|
+
gateway. The Ollama server must be reachable on that interface; a server listening
|
|
248
|
+
only on host loopback may need host networking instead. The package does not
|
|
249
|
+
change Ollama bindings, firewalls, or Docker settings.
|
|
250
|
+
|
|
251
|
+
For login on **native Linux Docker**, share the host network so the host browser
|
|
252
|
+
can reach the container's loopback listener:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
docker compose -f compose.yaml -f compose.login.yaml run --rm rosa-llm login --no-browser
|
|
256
|
+
docker compose run --rm rosa-llm status --provider openai --json
|
|
257
|
+
docker compose run --rm rosa-llm test --provider openai --json
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
`-f` selects Compose files; later files override earlier ones. Open the printed
|
|
261
|
+
authorization URL in the browser on that host. No callback port is publicly
|
|
262
|
+
published, and the listener remains on loopback. Do not run simultaneous logins
|
|
263
|
+
on the same port. Use `--port` to choose another port if needed.
|
|
264
|
+
|
|
265
|
+
Docker Desktop host networking requires its supported host-network feature to
|
|
266
|
+
be explicitly enabled; this project does not enable it. If unavailable, perform
|
|
267
|
+
initial login using the native WSL package, then transfer **your own** credential
|
|
268
|
+
directory into your private volume using your organization's secure file-transfer
|
|
269
|
+
process, preserving owner-only permissions and container UID 10001. Move the host
|
|
270
|
+
identity with its runtime; do not operate concurrent copies as independent hosts.
|
|
271
|
+
Alternatively use a Linux Docker host and an existing SSH tunnel as above.
|
|
272
|
+
Bridge networking alone with a listener bound to container `127.0.0.1` does not
|
|
273
|
+
make host loopback callbacks work; publishing a port does not fix that bind.
|
|
274
|
+
|
|
275
|
+
All commands for one installation must use the same Compose project and volume.
|
|
276
|
+
Do not share a credential volume between team members. Do not use
|
|
277
|
+
`docker compose down -v` unless you intend to delete those credentials (`-v`
|
|
278
|
+
removes named volumes). Bind mounts must be pre-owned by UID 10001 and mode 700.
|
|
279
|
+
Native Windows Python is outside this release's scope; use WSL or Linux containers.
|
|
280
|
+
|
|
281
|
+
## Architecture, dependencies, and credential storage
|
|
282
|
+
|
|
283
|
+
```text
|
|
284
|
+
src/rosa_llm/
|
|
285
|
+
config.py .env / per-user / process configuration
|
|
286
|
+
types.py Message, Tool, ToolCall, Response, StreamEvent
|
|
287
|
+
client.py create_client(), shared API, safe connection errors
|
|
288
|
+
langchain.py optional ChatRosaLLM adapter for LangChain/ROSA
|
|
289
|
+
providers.py Ollama NDJSON and OpenAI Responses SSE adapters
|
|
290
|
+
auth.py OAuth, loopback callback, JWT validation, renewal/revocation
|
|
291
|
+
storage.py owner-only atomic files and Linux process locking
|
|
292
|
+
http.py safe HTTP error classification
|
|
293
|
+
errors.py public exception types
|
|
294
|
+
cli.py developer commands and smoke checks
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Runtime dependencies are `httpx` for HTTP and streaming, `python-dotenv` for
|
|
298
|
+
configuration, and `PyJWT[crypto]` for RSA signature and claim validation.
|
|
299
|
+
`pytest` and `ruff` are development dependencies for tests and formatting/linting;
|
|
300
|
+
`uv_build` builds the installable package. The lock file includes transitive dependencies.
|
|
301
|
+
|
|
302
|
+
By default, `~/.config/rosa-llm/credentials.json` maps profile labels to separate
|
|
303
|
+
registrations and `host.json` persists a random host ID. `ROSA_LLM_AUTH_DIR`
|
|
304
|
+
overrides this location, which must be outside the project. Directories use mode
|
|
305
|
+
700; credential, host, temporary, and lock files use mode 600. Credential files
|
|
306
|
+
are plaintext protected by OS permissions, not encrypted at rest. Each successful
|
|
307
|
+
refresh atomically replaces the access token, rotating refresh token, scopes, and
|
|
308
|
+
expiry while holding a Linux process lock. A second process re-reads the new
|
|
309
|
+
record after obtaining the lock. Local filesystems are required; distributed/NFS
|
|
310
|
+
locking and multi-host credential sharing are outside scope.
|
|
311
|
+
|
|
312
|
+
Tokens are renewed near expiry. Revoked sessions require human login; temporary
|
|
313
|
+
network failures preserve credentials. No inference retries or provider fallbacks
|
|
314
|
+
are hidden in the client. HTTP redirects and environment proxy variables are
|
|
315
|
+
disabled on internally created HTTP clients; TLS verification remains enabled.
|
|
316
|
+
Do not enable HTTP wire/debug logging around OAuth because it can expose secrets.
|
|
317
|
+
|
|
318
|
+
## Automated checks and troubleshooting
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
uv run pytest -q
|
|
322
|
+
uv run ruff check .
|
|
323
|
+
uv run ruff format --check .
|
|
324
|
+
uv build
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`pytest -q` runs mocked tests with concise output; no live login or inference occurs.
|
|
328
|
+
Tests include signed JWTs, scope/state/nonce validation, rotation, multiprocess
|
|
329
|
+
refresh, storage permissions, provider streams/tool round trips, and CLI JSON.
|
|
330
|
+
Third-party pytest plugin auto-loading is disabled to isolate the suite from
|
|
331
|
+
ROS plugins present in sourced WSL shells. `ruff check` checks Python style and
|
|
332
|
+
common mistakes; `format --check` checks formatting without editing; `uv build`
|
|
333
|
+
creates a wheel and source distribution under `dist/`.
|
|
334
|
+
|
|
335
|
+
| Symptom | Action |
|
|
336
|
+
| --- | --- |
|
|
337
|
+
| Ollama connection refused in WSL | Check its actual host/port; Windows Ollama may need the WSL route gateway rather than localhost. Set `OLLAMA_BASE_URL` explicitly; there is no automatic endpoint switching. |
|
|
338
|
+
| Browser callback fails | Keep login running, check WSL forwarding or Docker host networking, and confirm the selected port is free. Use an existing SSH tunnel if needed. |
|
|
339
|
+
| Identity signed in, inference disabled | Reauthorize with `login --consent`; check account/workspace eligibility and granted plan permission. |
|
|
340
|
+
| Missing OpenAI model | Run `models --provider openai`; clear `OPENAI_MODEL` for catalog selection or use an available slug. |
|
|
341
|
+
| Usage limit/unavailable | Stop new requests and review [ChatGPT Usage](https://chatgpt.com/settings/usage); retry temporary unavailability later. The client does not bypass limits. |
|
|
342
|
+
| Token expired/revoked | Automatic refresh handles expiry; terminal refresh errors require `login` again with the same profile. |
|
|
343
|
+
| Credential permission error | Use a private directory owned by your OS user; files must be mode 600. Docker bind mounts must match UID 10001. |
|
|
344
|
+
| Partial stream followed by failure | Treat the request as failed; `generate()` never returns partial output as completed. |
|
|
345
|
+
| Unsupported feature | The native API supports text/history/function tools and OpenAI custom text tools. The optional LangChain adapter supports text/function tools. Hosted tools, images/files, native async HTTP clients and arbitrary OpenAI parameters are outside scope. |
|
|
346
|
+
|
|
347
|
+
The OpenAI implementation follows the official protocol, not Codex credentials
|
|
348
|
+
or unofficial ChatGPT endpoints. See [protocol sources](docs/protocol.md) and
|
|
349
|
+
[validation results and remaining manual checks](docs/validation.md).
|