@shipi18n/core 2.6.0 → 2.6.1
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.
- package/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/src/adapters/index.js +25 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @shipi18n/core
|
|
2
2
|
|
|
3
|
+
## 2.6.1
|
|
4
|
+
|
|
5
|
+
- Fix: the OpenAI adapter sent `max_tokens`, which current OpenAI models (gpt-5.x) reject with a
|
|
6
|
+
400 — `check --semantic -p openai` and `translate -p openai` failed against api.openai.com. The
|
|
7
|
+
adapter now sends `max_completion_tokens` to api.openai.com and keeps `max_tokens` for
|
|
8
|
+
OpenAI-compatible endpoints (Ollama, Gemini compat, LM Studio, vLLM), with a one-shot fallback
|
|
9
|
+
on the telltale 400 in either direction. Found by running the UIStringBench leaderboard against
|
|
10
|
+
live GPT judges.
|
|
11
|
+
|
|
3
12
|
## 2.6.0
|
|
4
13
|
|
|
5
14
|
- New: reporters (`humanReport`, `jsonReport`, `sarifReport`, `junitReport`, `REPORTERS`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipi18n/core",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Translation QA for i18n locale files: placeholder and plural validation, key parity, coverage, and an LLM-as-judge semantic review. Also a structure-preserving translation engine — bring your own OpenAI or Anthropic key.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/adapters/index.js
CHANGED
|
@@ -103,15 +103,35 @@ export function openaiAdapter(config = {}) {
|
|
|
103
103
|
return clientPromise
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
// Current OpenAI models (gpt-5.x era) reject `max_tokens` and require
|
|
107
|
+
// `max_completion_tokens`; OpenAI-compatible endpoints (Ollama, Gemini
|
|
108
|
+
// compat, LM Studio, vLLM) mostly still speak `max_tokens`. Try the modern
|
|
109
|
+
// name against api.openai.com and the legacy name against custom baseURLs,
|
|
110
|
+
// and fall back once on the telltale 400 either way.
|
|
111
|
+
let tokenParam = config.baseURL ? 'max_tokens' : 'max_completion_tokens'
|
|
106
112
|
return {
|
|
107
113
|
name: 'openai',
|
|
108
114
|
async complete(prompt, opts = {}) {
|
|
109
115
|
const client = await getClient()
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
const request = (param) =>
|
|
117
|
+
client.chat.completions.create({
|
|
118
|
+
model,
|
|
119
|
+
[param]: opts.maxTokens || 4096,
|
|
120
|
+
messages: [{ role: 'user', content: prompt }],
|
|
121
|
+
})
|
|
122
|
+
let res
|
|
123
|
+
try {
|
|
124
|
+
res = await request(tokenParam)
|
|
125
|
+
} catch (err) {
|
|
126
|
+
const msg = String(err?.message || '')
|
|
127
|
+
const other = tokenParam === 'max_tokens' ? 'max_completion_tokens' : 'max_tokens'
|
|
128
|
+
if (err?.status === 400 && msg.includes(other)) {
|
|
129
|
+
tokenParam = other // remember for subsequent calls
|
|
130
|
+
res = await request(other)
|
|
131
|
+
} else {
|
|
132
|
+
throw err
|
|
133
|
+
}
|
|
134
|
+
}
|
|
115
135
|
const content = res.choices?.[0]?.message?.content
|
|
116
136
|
if (!content) throw new Error('OpenAI response contained no content')
|
|
117
137
|
return content.trim()
|