Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

Every version, newest first. Each entry is the description of the pull request that made the change, which is written as a change note when the change is made.

## v1.60 (2026-09-15)

### A change log and release notes generated from pull request descriptions (#339)

Versions were tagged but never published as GitHub Releases, so the change record existed only as PR titles. Every merged PR here carries a description written as a change note, so the notes for a version are those descriptions in order, and the change log is the same for every version at once.

`scripts/release-notes.mjs` produces both from the tags and the gh CLI (`vX.Y` for one version, `--changelog` for all), mapping squash commits to PRs by the `(#N)` suffix and dropping attribution trailers. `CHANGELOG.md` is its output for all sixty versions to date. The README documents the release steps, and every existing tag is being published as a Release with these notes.

Also makes the run-watch test deterministic: it slept a fixed span and asserted a count band, which flaked on the macOS runner; it now waits for the give-up point and then proves no further polls happen.

### The provider probe no longer marks a healthy model family unavailable (#340)

The provider probe pinged with `max_tokens: 1`. One model family rejects every spelling of a token cap (`max_output_tokens` explicitly, `max_tokens` and `max_completion_tokens` behind the gateway's masked 400; measured earlier on `gpt-5.6-sol`), so the ping failed twice on its own parameter and the probe reported a reachable, unlocked provider as down. Every model of the family showed `[unavailable]` and the banner told the user to unlock a key that was never locked.

The ping now carries no cap. Cost is bounded by reading the streamed response only to its first frame, which is proof the provider answers, then aborting. A body that names a request parameter as the problem is classified as a reachable provider regardless of status, since a provider arguing about the request's shape is up. Locked and unavailable verdicts are unchanged.

Verified live against the cap-rejecting family on the gateway: the verdict is now ok. Tests: parameter rejection reads as up with no second ping; a healthy stream is read to one frame; existing locked, unlock-url, masked-twice, and cache cases still pass. 184 server tests pass.

## v1.59 (2026-09-12)

### A manual macOS job that builds GUFI and exercises its vector stack (#337)
Expand Down
4 changes: 2 additions & 2 deletions server/test/providerProbe.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ test('a provider that rejects the token-cap parameter is up, not unavailable', a
// read as a reachable provider either way.
reset()
responses.push({ status: 400, text: '{"error":{"message":"{\\"detail\\":\\"Unsupported parameter: max_output_tokens\\"}","type":"error"}}' })
const v = await probeProvider('me:army', 'me:army/gpt-5.6-luna-gov', 'k7')
const v = await probeProvider('me:vega', 'me:vega/model-a', 'k7')
assert.deepEqual([v.ok, v.kind], [true, null])
assert.equal(calls.length, 1, 'no second ping needed for a parameter complaint')
})
Expand All @@ -91,7 +91,7 @@ test('a healthy stream is read only to its first frame', async () => {
calls.push({ url: String(url), body: init?.body ? JSON.parse(init.body) : null })
return { ok: true, status: 200, body, text: async () => frames.join('') }
}
const v = await probeProvider('me:army', 'me:army/gpt-5.6-terra-gov', 'k8')
const v = await probeProvider('me:vega', 'me:vega/model-b', 'k8')
assert.equal(v.ok, true)
assert.ok(pulls <= 1, `read ${pulls} chunks; one frame is proof enough`)
globalThis.fetch = async (url, init) => {
Expand Down
Loading