Split README into user guide and DEVELOPMENT.md
This commit is contained in:
parent
75d15827ab
commit
8172f41c56
3 changed files with 144 additions and 58 deletions
78
DEVELOPMENT.md
Normal file
78
DEVELOPMENT.md
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Development
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm install
|
||||||
|
pnpm run ci # type check + tests
|
||||||
|
```
|
||||||
|
|
||||||
|
To test your checkout in pi, install it from the local path:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pi install /absolute/path/to/pi-unigpt
|
||||||
|
```
|
||||||
|
|
||||||
|
Changes take effect after `/reload`.
|
||||||
|
|
||||||
|
Tests use fake keys, mocked discovery, and a local HTTP server. They never
|
||||||
|
contact uniGPT or read your pi configuration.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
| --- | --- |
|
||||||
|
| `src/provider.ts` | The pi provider: login, model discovery, model metadata |
|
||||||
|
| `src/index.ts` | Extension entry point and the `/unigpt-refresh` command |
|
||||||
|
| `test/provider.test.ts` | Discovery, login, caching, and transport tests |
|
||||||
|
| `test/command.test.ts` | `/unigpt-refresh` behavior |
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
**Endpoints.** The API base is
|
||||||
|
`https://api.mygpt.uni-graz.at/api/v1/llms/openai`. Discovery calls
|
||||||
|
`GET /models` with bearer auth; inference uses pi's built-in OpenAI
|
||||||
|
Responses transport on `POST /responses`. Every request must also carry a
|
||||||
|
`deployment-id` header naming the model, which each discovered model sets.
|
||||||
|
|
||||||
|
**Model metadata.** `/models` returns only IDs (e.g. `gpt-5.4`). Those IDs
|
||||||
|
are OpenAI model names, so `lookupCatalogMetadata` reads name, context
|
||||||
|
window, output limit, and image support from pi's bundled catalog
|
||||||
|
(`openai` and `azure` providers), taking the smaller value where the two
|
||||||
|
differ. This keeps the extension free of a hardcoded model table: new
|
||||||
|
models get correct limits when pi updates. Unknown IDs fall back to pi's
|
||||||
|
defaults for custom models (128k context, 16k output, text only).
|
||||||
|
|
||||||
|
The uniGPT web app has richer endpoints
|
||||||
|
(`/api/v1/tenants/uni/ai-models[/detailed]`) and an OpenAPI spec
|
||||||
|
(`/api/v1/docs/openapi.yaml`), but they require a browser session token
|
||||||
|
and reject API keys. If uniGPT ever exposes limits to API keys, prefer
|
||||||
|
them over the catalog lookup.
|
||||||
|
|
||||||
|
**Reasoning.** uniGPT ignores `reasoning.effort` and applies a fixed effort
|
||||||
|
per deployment (verified against the live API), so every model sets
|
||||||
|
`reasoning: false` to avoid offering thinking levels that do nothing.
|
||||||
|
|
||||||
|
**Caching and errors.** pi persists the discovered catalog and restores it
|
||||||
|
offline. A failed or malformed refresh keeps the previous catalog; single
|
||||||
|
malformed entries are skipped. Error messages never include the API key or
|
||||||
|
server response bodies.
|
||||||
|
|
||||||
|
**Login.** `/login unigpt` validates the key against `/models` before pi
|
||||||
|
stores it. Validation always uses the default endpoint, even if a user
|
||||||
|
overrides `baseUrl` in `models.json`.
|
||||||
|
|
||||||
|
## Known server-side issues
|
||||||
|
|
||||||
|
As of November 2026, `gpt-5-nano` and `gpt-4.1-nano` return HTTP 500
|
||||||
|
(`'NoneType' object has no attribute 'decrypt'`) for every request.
|
||||||
|
|
||||||
|
## Releasing
|
||||||
|
|
||||||
|
1. Run `pnpm run ci`.
|
||||||
|
2. Bump `version` in `package.json` and commit.
|
||||||
|
3. Tag and push: `git tag vX.Y.Z && git push origin main vX.Y.Z`.
|
||||||
|
4. Update the version in the README's "Pinning a version" example.
|
||||||
|
|
||||||
|
CI is defined in `.gitea/workflows/ci.yml` and runs once Gitea Actions are
|
||||||
|
enabled for the repository.
|
||||||
123
README.md
123
README.md
|
|
@ -1,16 +1,16 @@
|
||||||
# pi-unigpt
|
# pi-unigpt
|
||||||
|
|
||||||
Use [uniGPT](https://unigpt.uni-graz.at), the University of Graz's AI
|
Use [uniGPT](https://unigpt.uni-graz.at), the University of Graz's AI
|
||||||
platform, as a model provider in [pi](https://pi.dev).
|
assistant, inside the [pi](https://pi.dev) coding agent.
|
||||||
|
|
||||||
Models are discovered automatically, and their limits come from pi's model
|
Once set up, every model your uniGPT account offers appears in pi's model
|
||||||
catalog, so there is no model list to maintain. Tool calling, streaming, and
|
picker, including GPT-4o, GPT-4.1, and the GPT-5 and GPT-6 families. Tools,
|
||||||
image input work.
|
streaming responses, and image input all work.
|
||||||
|
|
||||||
## Requirements
|
## What you need
|
||||||
|
|
||||||
- pi **1.5.x** and Node.js **22.19+**
|
- **pi 1.5 or newer** ([installation guide](https://pi.dev))
|
||||||
- A uniGPT **API key**. If you don't have one, ask the uniGPT team at the
|
- **A uniGPT API key.** If you don't have one, ask the uniGPT team at the
|
||||||
[IDea_Lab](https://idea-lab.uni-graz.at/en/digital-innovation-lab/unigpt-and-studigpt).
|
[IDea_Lab](https://idea-lab.uni-graz.at/en/digital-innovation-lab/unigpt-and-studigpt).
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
@ -21,27 +21,25 @@ image input work.
|
||||||
pi install git:imsc.uni-graz.at/git/behackl/pi-unigpt
|
pi install git:imsc.uni-graz.at/git/behackl/pi-unigpt
|
||||||
```
|
```
|
||||||
|
|
||||||
To stay on a fixed release instead of following the latest version, add the
|
|
||||||
tag: `…/pi-unigpt@v0.1.0`.
|
|
||||||
|
|
||||||
**2. Log in**
|
**2. Log in**
|
||||||
|
|
||||||
Start pi (or run `/reload` if it is already running) and enter:
|
Start pi (or type `/reload` if it is already running), then type:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/login unigpt
|
/login unigpt
|
||||||
```
|
```
|
||||||
|
|
||||||
Paste your API key into the masked dialog, **not into the chat**. Pi checks
|
A dialog asks for your API key. Paste it there, **not into the chat**. Pi
|
||||||
the key and reports how many models it can use.
|
checks the key and tells you how many models you can use.
|
||||||
|
|
||||||
**3. Pick a model**
|
**3. Pick a model**
|
||||||
|
|
||||||
Run `/model` and choose one of the models listed under `unigpt`.
|
Type `/model` and choose one of the models listed under **unigpt**.
|
||||||
|
|
||||||
**4. Optional: make uniGPT your default**
|
That's it. Pi remembers your key and your last model for next time.
|
||||||
|
|
||||||
Add this to `~/.pi/agent/settings.json` to start pi with a uniGPT model:
|
**Optional: start pi with uniGPT by default.** Add this to
|
||||||
|
`~/.pi/agent/settings.json`, using any model from the list:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -52,18 +50,48 @@ Add this to `~/.pi/agent/settings.json` to start pi with a uniGPT model:
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
| Command | Purpose |
|
| Command | What it does |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `/login unigpt` | Save and verify your API key |
|
| `/login unigpt` | Save your API key (or replace it with a new one) |
|
||||||
| `/model` | Pick a model (also reloads the model list) |
|
| `/model` | Choose a model |
|
||||||
| `/unigpt-refresh` | Reload the model list and report any problem |
|
| `/unigpt-refresh` | Reload the list of models, e.g. after uniGPT adds new ones |
|
||||||
| `/logout` | Remove the saved key from pi (it stays valid at uniGPT) |
|
| `/logout` | Remove your key from pi (the key itself stays valid) |
|
||||||
|
|
||||||
## Keeping your key out of auth.json
|
## Updating
|
||||||
|
|
||||||
Pi saves the key unencrypted in `~/.pi/agent/auth.json`, readable only by
|
```sh
|
||||||
your user account. To avoid that, edit the `unigpt` entry there to read the
|
pi update --extensions
|
||||||
key from an environment variable or a password manager:
|
```
|
||||||
|
|
||||||
|
## Things to know
|
||||||
|
|
||||||
|
- **The thinking level setting has no effect.** uniGPT decides how much each
|
||||||
|
model reasons; models that reason still do so.
|
||||||
|
- **Costs are shown as zero.** Pi doesn't track uniGPT usage; this does not
|
||||||
|
mean usage is unlimited. Your university's usage rules still apply.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **No uniGPT models in `/model`:** type `/unigpt-refresh`. It tells you
|
||||||
|
what is wrong, e.g. a rejected key or no network connection.
|
||||||
|
- **One model always fails with an error:** that model may be unavailable
|
||||||
|
on uniGPT's side. Pick another one and let the uniGPT team know.
|
||||||
|
- **`pi -p "…"` says a uniGPT model was not found:** start pi normally once
|
||||||
|
after logging in, so it can load the model list.
|
||||||
|
- **Installation fails with `spawn npm ENOENT`:** you use pnpm instead of
|
||||||
|
npm. Add `"npmCommand": ["pnpm"]` to `~/.pi/agent/settings.json` and try
|
||||||
|
again.
|
||||||
|
|
||||||
|
Still stuck? [Open an issue](https://imsc.uni-graz.at/git/behackl/pi-unigpt/issues)
|
||||||
|
with the output of `/unigpt-refresh` and the model you used. **Never include
|
||||||
|
your API key.**
|
||||||
|
|
||||||
|
## Advanced
|
||||||
|
|
||||||
|
**Storing the key elsewhere.** Pi saves your key unencrypted in
|
||||||
|
`~/.pi/agent/auth.json`, readable only by your user account. To keep it out
|
||||||
|
of that file, change the `unigpt` entry there to read it from an environment
|
||||||
|
variable or a password manager command:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "unigpt": { "type": "api_key", "key": "${UNIGPT_API_KEY}" } }
|
{ "unigpt": { "type": "api_key", "key": "${UNIGPT_API_KEY}" } }
|
||||||
|
|
@ -73,42 +101,21 @@ key from an environment variable or a password manager:
|
||||||
{ "unigpt": { "type": "api_key", "key": "!op read op://Private/uniGPT/credential" } }
|
{ "unigpt": { "type": "api_key", "key": "!op read op://Private/uniGPT/credential" } }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Good to know
|
**Adjusting model limits.** Pi knows the context size and output limit of
|
||||||
|
common models. For a model it doesn't recognize, it assumes 128k tokens of
|
||||||
|
context and 16k of output. If you know better, override them in
|
||||||
|
`~/.pi/agent/models.json`:
|
||||||
|
|
||||||
- **Thinking levels are off.** uniGPT applies a fixed reasoning effort per
|
```json
|
||||||
model and ignores pi's setting. Reasoning models still reason.
|
{ "providers": { "unigpt": { "modelOverrides": { "gpt-5.4": { "contextWindow": 200000 } } } } }
|
||||||
- **Costs show as zero.** That means "not tracked", not "free".
|
|
||||||
- **Model limits** come from pi's catalog. Models pi doesn't know get 128k
|
|
||||||
context and 16k output; update pi to pick up newer ones. To override a
|
|
||||||
value, use `modelOverrides` in `~/.pi/agent/models.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "providers": { "unigpt": { "modelOverrides": { "gpt-5.4": { "contextWindow": 200000 } } } } }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
- **No uniGPT models in `/model`:** run `/unigpt-refresh`; it names the
|
|
||||||
problem (rejected key, unreachable server, empty model list).
|
|
||||||
- **`pi -p` can't find a uniGPT model:** print mode doesn't fetch model
|
|
||||||
lists. Start pi interactively once after logging in.
|
|
||||||
- **One model fails with HTTP 500:** that deployment is broken on the
|
|
||||||
server; pick another model and tell the uniGPT team.
|
|
||||||
- **Install fails with `spawn npm ENOENT`:** you use pnpm instead of npm.
|
|
||||||
Add `"npmCommand": ["pnpm"]` to `~/.pi/agent/settings.json`.
|
|
||||||
|
|
||||||
Report bugs at <https://imsc.uni-graz.at/git/behackl/pi-unigpt/issues>.
|
|
||||||
Include the `/unigpt-refresh` output and the model you used, never your
|
|
||||||
API key.
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm install
|
|
||||||
pnpm run ci # type check + tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests use fake keys and a local server; they never contact uniGPT.
|
**Pinning a version.** To stay on one release, install with its tag, e.g.
|
||||||
|
`pi install git:imsc.uni-graz.at/git/behackl/pi-unigpt@v0.1.0`.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [DEVELOPMENT.md](DEVELOPMENT.md).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
"README.md",
|
"README.md",
|
||||||
"LICENSE"
|
"LICENSE",
|
||||||
|
"DEVELOPMENT.md"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.19.0"
|
"node": ">=22.19.0"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue