101 lines
4 KiB
Markdown
101 lines
4 KiB
Markdown
# 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`.
|
||
|
||
## Compatibility
|
||
|
||
Supported: pi 1.3 and newer (`peerDependencies`). Development pins pi 1.5.
|
||
On 1.0–1.2 the tests pass and a live session worked, but `pnpm run check`
|
||
fails: pi's `Provider` typing rejects this provider, and 1.0–1.1 also lack
|
||
`RefreshModelsContext.baseUrl`, so `baseUrl` overrides are ignored there. To check another version, pin both
|
||
`@earendil-works/*` dev dependencies to it and run `pnpm run ci`.
|
||
|
||
## 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
|
||
|
||
CI is defined in `.github/workflows/ci.yml`, which Gitea Actions reads as
|
||
well. It runs once Actions are enabled for the repository and a runner is
|
||
available.
|
||
|
||
The workflow checks out code with `ischanx/checkout`, not
|
||
`actions/checkout`. Upstream builds the clone URL from the server's origin
|
||
and drops the `/git` subpath of imsc.uni-graz.at, so cloning fails
|
||
([actions/checkout#1370](https://github.com/actions/checkout/issues/1370)).
|
||
The fork's v6.0.2 tag fixes that; its v4 tags are identical to upstream and
|
||
do not. The action is pinned to a commit hash because it runs with the CI
|
||
token. When upgrading, review the fork's diff against upstream first.
|
||
|
||
All actions are referenced by full URL (`uses: https://github.com/...`).
|
||
Short names like `actions/setup-node@v4` would be looked up in the
|
||
instance's default actions registry instead of on GitHub.
|