@monotykamary/pi-opencode-provider 1.0.5 → 1.0.7
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/AGENTS.md +1 -0
- package/README.md +16 -6
- package/deprecated-models.json +1 -0
- package/index.ts +34 -1
- package/models.json +540 -389
- package/package.json +1 -1
- package/patch.json +530 -62
- package/scripts/update-models.js +107 -2
package/scripts/update-models.js
CHANGED
|
@@ -103,6 +103,46 @@ function convertModel(model) {
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
// Load a layered JSON model file.
|
|
107
|
+
function loadJson(fileName) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(fs.readFileSync(path.join(process.cwd(), fileName), 'utf8'));
|
|
110
|
+
} catch {
|
|
111
|
+
return fileName === 'patch.json' ? {} : [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Deep-merge patch overrides into a model for README documentation. The
|
|
116
|
+
// generated models.json remains API-derived; only the displayed model map uses patches.
|
|
117
|
+
function applyPatch(model, patch) {
|
|
118
|
+
if (!patch) return model;
|
|
119
|
+
const result = { ...model };
|
|
120
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
121
|
+
if (key === 'cost' || key === 'compat' || key === 'thinkingLevelMap') {
|
|
122
|
+
result[key] = { ...(result[key] || {}), ...value };
|
|
123
|
+
} else {
|
|
124
|
+
result[key] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!result.reasoning) {
|
|
128
|
+
delete result.thinkingLevelMap;
|
|
129
|
+
if (result.compat?.thinkingFormat) delete result.compat.thinkingFormat;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Merge API models, patches, and custom models in the same order as index.ts.
|
|
135
|
+
function buildModels(baseModels, customModels, patch) {
|
|
136
|
+
const byId = new Map(baseModels.map(model => [model.id, model]));
|
|
137
|
+
for (const [id, entry] of Object.entries(patch)) {
|
|
138
|
+
if (byId.has(id)) byId.set(id, applyPatch(byId.get(id), entry));
|
|
139
|
+
}
|
|
140
|
+
for (const model of customModels) {
|
|
141
|
+
byId.set(model.id, applyPatch(model, patch[model.id]));
|
|
142
|
+
}
|
|
143
|
+
return Array.from(byId.values());
|
|
144
|
+
}
|
|
145
|
+
|
|
106
146
|
// Generate README model table row
|
|
107
147
|
function generateReadmeRow(model) {
|
|
108
148
|
const cost = model.cost || {};
|
|
@@ -151,6 +191,67 @@ ${tableRows}`;
|
|
|
151
191
|
console.log(` Updated README.md with ${models.length} models`);
|
|
152
192
|
}
|
|
153
193
|
|
|
194
|
+
// Grace period for delisted models: update-models.js moves models the API no
|
|
195
|
+
// longer lists into deprecated-models.json (stamped with deprecatedAt) instead
|
|
196
|
+
// of dropping them; the runtime appends them back so sessions and saved model
|
|
197
|
+
// settings keep working, and after 14 days they are evicted permanently.
|
|
198
|
+
const DEPRECATED_MODEL_TTL_MS = 14 * 24 * 60 * 60 * 1000;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Reconcile deprecated-models.json against the freshly fetched model list.
|
|
202
|
+
* - in old models.json but not the API: moved into the deprecated file
|
|
203
|
+
* (deprecatedAt = now; preserved on repeat runs so the grace clock is not reset)
|
|
204
|
+
* - back in the API: resurrected (dropped from the deprecated file)
|
|
205
|
+
* - deprecatedAt older than 14 days: evicted permanently
|
|
206
|
+
* Must run BEFORE the new models.json is written; it reads the old file itself.
|
|
207
|
+
*/
|
|
208
|
+
function updateDeprecatedModels(modelsJsonPath, newModels) {
|
|
209
|
+
const deprecatedPath = path.join(path.dirname(modelsJsonPath), 'deprecated-models.json');
|
|
210
|
+
|
|
211
|
+
let oldModels = [];
|
|
212
|
+
try {
|
|
213
|
+
const parsed = JSON.parse(fs.readFileSync(modelsJsonPath, 'utf8'));
|
|
214
|
+
if (Array.isArray(parsed)) oldModels = parsed;
|
|
215
|
+
} catch { /* first run: no previous models.json */ }
|
|
216
|
+
|
|
217
|
+
let deprecated = {};
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(fs.readFileSync(deprecatedPath, 'utf8'));
|
|
220
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) deprecated = parsed;
|
|
221
|
+
} catch { /* no graveyard yet */ }
|
|
222
|
+
|
|
223
|
+
const currentIds = new Set(newModels.map(m => m.id));
|
|
224
|
+
const now = new Date().toISOString();
|
|
225
|
+
const added = [];
|
|
226
|
+
const resurrected = [];
|
|
227
|
+
const evicted = [];
|
|
228
|
+
|
|
229
|
+
for (const old of oldModels) {
|
|
230
|
+
if (old && old.id && !currentIds.has(old.id) && !deprecated[old.id]) {
|
|
231
|
+
deprecated[old.id] = { ...old, deprecatedAt: now };
|
|
232
|
+
added.push(old.id);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
for (const [id, entry] of Object.entries(deprecated)) {
|
|
237
|
+
if (currentIds.has(id)) {
|
|
238
|
+
delete deprecated[id];
|
|
239
|
+
resurrected.push(id);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const removedAt = Date.parse(entry && entry.deprecatedAt ? entry.deprecatedAt : '');
|
|
243
|
+
if (Number.isNaN(removedAt) || Date.now() - removedAt > DEPRECATED_MODEL_TTL_MS) {
|
|
244
|
+
delete deprecated[id];
|
|
245
|
+
evicted.push(id);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (added.length > 0 || resurrected.length > 0 || evicted.length > 0) {
|
|
250
|
+
fs.writeFileSync(deprecatedPath, JSON.stringify(deprecated, null, 2) + '\n');
|
|
251
|
+
console.log('Updated deprecated-models.json ' + JSON.stringify({ added, resurrected, evicted }));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
154
255
|
async function main() {
|
|
155
256
|
console.log('Fetching models from API...');
|
|
156
257
|
|
|
@@ -174,11 +275,15 @@ async function main() {
|
|
|
174
275
|
// Convert to Pi-native format and save to models.json
|
|
175
276
|
const models = apiModels.map(convertModel);
|
|
176
277
|
const modelsPath = path.join(process.cwd(), 'models.json');
|
|
278
|
+
// Move delisted models to deprecated-models.json BEFORE models.json is overwritten
|
|
279
|
+
updateDeprecatedModels(modelsPath, models);
|
|
177
280
|
fs.writeFileSync(modelsPath, JSON.stringify(models, null, 2) + '\n');
|
|
178
281
|
console.log(` Saved ${models.length} models to models.json`);
|
|
179
282
|
|
|
180
|
-
//
|
|
181
|
-
|
|
283
|
+
// Apply layered overrides for documentation: models.json → patch.json → custom-models.json.
|
|
284
|
+
const patch = loadJson('patch.json');
|
|
285
|
+
const customModels = Array.isArray(loadJson('custom-models.json')) ? loadJson('custom-models.json') : [];
|
|
286
|
+
updateReadme(buildModels(models, customModels, patch));
|
|
182
287
|
|
|
183
288
|
console.log('\nDone!');
|
|
184
289
|
} catch (error) {
|