@genee/omp-opsx-addon 0.7.0 → 0.9.0
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/README.md +441 -71
- package/index.ts +1030 -208
- package/lib/agent-defs.ts +55 -82
- package/lib/complexity-router.ts +336 -0
- package/lib/concurrency-control.ts +1246 -0
- package/lib/concurrency-multiproc.worker.ts +376 -0
- package/lib/concurrency-state.ts +397 -0
- package/lib/concurrency-tuner.ts +773 -0
- package/lib/concurrency-writer.ts +894 -0
- package/lib/continuity-guard.ts +117 -0
- package/lib/direct-fetchers.ts +18 -3
- package/lib/family-filter.ts +115 -2
- package/lib/model-roles.ts +41 -39
- package/lib/model-selector.ts +300 -36
- package/lib/model-speed.ts +189 -0
- package/lib/pick-model-render.ts +414 -0
- package/lib/pipe-core.ts +325 -98
- package/lib/pipe-push.ts +136 -5
- package/lib/provider-variants.ts +154 -0
- package/lib/selection-filters.ts +42 -1
- package/lib/stall-detector.ts +185 -0
- package/lib/system-prompt.ts +17 -9
- package/lib/tiers-data.ts +40 -5
- package/lib/tiers-updater.ts +51 -8
- package/lib/unified-config.ts +732 -27
- package/lib/usage-poller.ts +44 -1
- package/lib/usage-render.ts +57 -4
- package/lib/usage-widget.ts +18 -4
- package/package.json +1 -1
- package/skills/opsx-orchestration-protocol/SKILL.md +87 -0
package/lib/tiers-data.ts
CHANGED
|
@@ -8,7 +8,20 @@
|
|
|
8
8
|
import { readFileSync } from 'node:fs';
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
10
|
import { join } from 'node:path';
|
|
11
|
-
import type
|
|
11
|
+
import { TIER_RANK, rankToTierName, type TierName } from './model-tiers.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Variant guard suffix table used when the data file omits `variant_suffixes`.
|
|
15
|
+
* Semantics: a model id whose LAST hyphen-separated segment is one of these
|
|
16
|
+
* suffixes is a downgraded variant of its family (glm-5.3-flash, gpt-5.4-mini,
|
|
17
|
+
* …); a family-wide glob catching such a variant must not hand it the
|
|
18
|
+
* flagship tier (see the guard in `matchDataEntry`). Variant-specific
|
|
19
|
+
* selectors (exact ids, provider-scoped ids, or globs ending in the suffix)
|
|
20
|
+
* are deliberate declarations and bypass the guard.
|
|
21
|
+
*/
|
|
22
|
+
export const DEFAULT_VARIANT_SUFFIXES: readonly string[] = [
|
|
23
|
+
'flash', 'highspeed', 'air', 'mini', 'turbo', 'lite', 'nano', 'instant', 'free',
|
|
24
|
+
];
|
|
12
25
|
|
|
13
26
|
// ── types ────────────────────────────────────────────────────────────
|
|
14
27
|
|
|
@@ -23,6 +36,8 @@ interface TierDataFile {
|
|
|
23
36
|
version: number;
|
|
24
37
|
updated: string;
|
|
25
38
|
entries: TierDataEntry[];
|
|
39
|
+
/** Optional. Suffix table governing the glob variant guard; defaults to `DEFAULT_VARIANT_SUFFIXES`. */
|
|
40
|
+
variant_suffixes?: string[];
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
// ── state ────────────────────────────────────────────────────────────
|
|
@@ -79,12 +94,27 @@ export function matchDataEntry(
|
|
|
79
94
|
const bare = data.entries.find((e) => e.selector === modelId);
|
|
80
95
|
if (bare) return { tier: bare.tier, reputation: bare.reputation, reason: `data: ${bare.selector}` };
|
|
81
96
|
|
|
82
|
-
// 3. Glob patterns (in order)
|
|
97
|
+
// 3. Glob patterns (in order). A family-wide glob catching an un-enumerated
|
|
98
|
+
// downgraded variant (last hyphen segment in the suffix table) is
|
|
99
|
+
// deterministically demoted one tier instead of riding the flagship
|
|
100
|
+
// rank; globs ending in the suffix are variant-specific declarations
|
|
101
|
+
// and pass through unchanged.
|
|
102
|
+
const suffixes = data.variant_suffixes ?? DEFAULT_VARIANT_SUFFIXES;
|
|
83
103
|
const globs = data.entries.filter((e) => hasGlob(e.selector));
|
|
84
104
|
for (const g of globs) {
|
|
85
|
-
if (globMatch(g.selector, modelId))
|
|
86
|
-
|
|
105
|
+
if (!globMatch(g.selector, modelId)) continue;
|
|
106
|
+
const lastSegment = (modelId.split('-').pop() ?? '').toLowerCase();
|
|
107
|
+
const isVariant = lastSegment !== '' && suffixes.includes(lastSegment);
|
|
108
|
+
const variantSpecific = g.selector.toLowerCase().endsWith(lastSegment);
|
|
109
|
+
if (isVariant && !variantSpecific) {
|
|
110
|
+
const rank = Math.max(TIER_RANK[g.tier] - 1, TIER_RANK.tiny);
|
|
111
|
+
return {
|
|
112
|
+
tier: rankToTierName(rank),
|
|
113
|
+
reputation: Math.max(0, g.reputation - 20),
|
|
114
|
+
reason: `data: ${g.selector} (variant guard)`,
|
|
115
|
+
};
|
|
87
116
|
}
|
|
117
|
+
return { tier: g.tier, reputation: g.reputation, reason: `data: ${g.selector}` };
|
|
88
118
|
}
|
|
89
119
|
|
|
90
120
|
return null;
|
|
@@ -111,7 +141,12 @@ function ensureLoaded(): TierDataFile | null {
|
|
|
111
141
|
const raw = readFileSync(CACHE_PATH, 'utf-8');
|
|
112
142
|
const parsed = JSON.parse(raw) as TierDataFile;
|
|
113
143
|
if (!Array.isArray(parsed.entries)) throw new Error('missing entries array');
|
|
114
|
-
|
|
144
|
+
// Normalize the optional suffix table: malformed values fall back to
|
|
145
|
+
// the built-in defaults rather than disabling the guard.
|
|
146
|
+
const suffixes = Array.isArray(parsed.variant_suffixes)
|
|
147
|
+
? parsed.variant_suffixes.filter((s): s is string => typeof s === 'string' && s.length > 0)
|
|
148
|
+
: [...DEFAULT_VARIANT_SUFFIXES];
|
|
149
|
+
_data = { ...parsed, variant_suffixes: suffixes };
|
|
115
150
|
_loadError = null;
|
|
116
151
|
} catch (err) {
|
|
117
152
|
_data = null;
|
package/lib/tiers-updater.ts
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* when the cache is missing or stale (> 7 days).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
8
|
+
import { writeFileSync, mkdirSync, existsSync, renameSync, unlinkSync } from 'node:fs';
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
10
|
import { join, dirname } from 'node:path';
|
|
11
11
|
import type { TierDataEntry } from './tiers-data.js';
|
|
12
|
-
import { reloadTierData, TIERS_DATA_PATH, tiersDataAge, isTiersDataLoaded } from './tiers-data.js';
|
|
12
|
+
import { DEFAULT_VARIANT_SUFFIXES, reloadTierData, TIERS_DATA_PATH, tiersDataAge, isTiersDataLoaded } from './tiers-data.js';
|
|
13
13
|
|
|
14
14
|
// ── constants ────────────────────────────────────────────────────────
|
|
15
15
|
|
|
@@ -36,7 +36,6 @@ const SEED_ENTRIES: TierDataEntry[] = [
|
|
|
36
36
|
// ── deepseek ───────────────────────────────────
|
|
37
37
|
{ selector: 'deepseek/deepseek-v4-pro', tier: 'top', reputation: 70 },
|
|
38
38
|
{ selector: 'deepseek/deepseek-v4-flash', tier: 'mid', reputation: 45 },
|
|
39
|
-
{ selector: 'deepseek/deepseek-v4-pro', tier: 'top', reputation: 70 },
|
|
40
39
|
|
|
41
40
|
// ── minimax ────────────────────────────────────
|
|
42
41
|
{ selector: 'MiniMax-M3', tier: 'top', reputation: 60 },
|
|
@@ -51,6 +50,10 @@ const SEED_ENTRIES: TierDataEntry[] = [
|
|
|
51
50
|
{ selector: 'kimi-k*', tier: 'top', reputation: 60 },
|
|
52
51
|
|
|
53
52
|
// ── zhipu / glm ────────────────────────────────
|
|
53
|
+
// Downgraded variants are enumerated explicitly so they take the mid band
|
|
54
|
+
// (bare id beats the `glm-5.*` family glob) instead of the flagship top/68.
|
|
55
|
+
{ selector: 'glm-5.3-flash', tier: 'mid', reputation: 45 },
|
|
56
|
+
{ selector: 'glm-5.3-highspeed', tier: 'mid', reputation: 45 },
|
|
54
57
|
{ selector: 'glm-5.2', tier: 'top', reputation: 70 },
|
|
55
58
|
{ selector: 'glm-5.*', tier: 'top', reputation: 68 },
|
|
56
59
|
{ selector: 'glm-4.7', tier: 'mid', reputation: 50 },
|
|
@@ -117,29 +120,69 @@ export interface UpdateResult {
|
|
|
117
120
|
error?: string;
|
|
118
121
|
}
|
|
119
122
|
|
|
123
|
+
/** Payload written to the cache file. */
|
|
124
|
+
interface TiersPayload {
|
|
125
|
+
version: number;
|
|
126
|
+
updated: string;
|
|
127
|
+
variant_suffixes: string[];
|
|
128
|
+
entries: TierDataEntry[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Full integrity/format check on the payload BEFORE it may replace the cache.
|
|
133
|
+
* Returns an error message, or null when the payload is safe to write.
|
|
134
|
+
*/
|
|
135
|
+
function validatePayload(data: TiersPayload): string | null {
|
|
136
|
+
if (data.version !== 1) return `unsupported version: ${data.version}`;
|
|
137
|
+
if (typeof data.updated !== 'string' || Number.isNaN(Date.parse(data.updated))) return 'missing/invalid updated timestamp';
|
|
138
|
+
if (!Array.isArray(data.variant_suffixes) || data.variant_suffixes.length === 0) return 'missing variant_suffixes';
|
|
139
|
+
if (!Array.isArray(data.entries) || data.entries.length === 0) return 'empty entries array';
|
|
140
|
+
const seen = new Set<string>();
|
|
141
|
+
for (const e of data.entries) {
|
|
142
|
+
if (typeof e.selector !== 'string' || !e.selector.trim()) return `invalid selector: ${JSON.stringify(e)}`;
|
|
143
|
+
if (typeof e.reputation !== 'number' || !Number.isFinite(e.reputation) || e.reputation < 0) return `invalid reputation for ${e.selector}`;
|
|
144
|
+
if (seen.has(e.selector)) return `duplicate selector: ${e.selector}`;
|
|
145
|
+
seen.add(e.selector);
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
120
150
|
/**
|
|
121
151
|
* Write seed tier data to the cache file.
|
|
122
152
|
* Creates parent directories as needed.
|
|
153
|
+
* The payload is validated first, and written via a temp file + rename so a
|
|
154
|
+
* failed write never clobbers an existing cache.
|
|
123
155
|
*/
|
|
124
156
|
export function updateTiers(opts?: { silent?: boolean }): UpdateResult {
|
|
125
157
|
const path = TIERS_DATA_PATH;
|
|
158
|
+
const tmpPath = `${path}.tmp`;
|
|
126
159
|
try {
|
|
127
|
-
const
|
|
128
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
129
|
-
|
|
130
|
-
const data = {
|
|
160
|
+
const data: TiersPayload = {
|
|
131
161
|
version: 1,
|
|
132
162
|
updated: new Date().toISOString(),
|
|
163
|
+
variant_suffixes: [...DEFAULT_VARIANT_SUFFIXES],
|
|
133
164
|
entries: SEED_ENTRIES,
|
|
134
165
|
};
|
|
135
166
|
|
|
136
|
-
|
|
167
|
+
const invalid = validatePayload(data);
|
|
168
|
+
if (invalid) return { ok: false, path, count: 0, error: `refusing to write: ${invalid}` };
|
|
169
|
+
|
|
170
|
+
const dir = dirname(path);
|
|
171
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
172
|
+
|
|
173
|
+
writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
174
|
+
renameSync(tmpPath, path);
|
|
137
175
|
|
|
138
176
|
// Force runtime to reload on next access
|
|
139
177
|
reloadTierData();
|
|
140
178
|
|
|
141
179
|
return { ok: true, path, count: SEED_ENTRIES.length };
|
|
142
180
|
} catch (err) {
|
|
181
|
+
try {
|
|
182
|
+
if (existsSync(tmpPath)) unlinkSync(tmpPath);
|
|
183
|
+
} catch {
|
|
184
|
+
// best-effort cleanup; the original error below matters more
|
|
185
|
+
}
|
|
143
186
|
const msg = err instanceof Error ? err.message : String(err);
|
|
144
187
|
return { ok: false, path, count: 0, error: msg };
|
|
145
188
|
}
|