ultimate-pi 0.2.7 → 0.3.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/.agents/skills/harness-eval/SKILL.md +1 -1
- package/.agents/skills/harness-governor/SKILL.md +2 -2
- package/.agents/skills/harness-spec/SKILL.md +1 -1
- package/.pi/PACKAGING.md +3 -2
- package/.pi/extensions/custom-header.ts +0 -17
- package/.pi/extensions/pi-model-router-harness.ts +42 -0
- package/.pi/extensions/policy-gate.ts +18 -0
- package/.pi/extensions/provider-payload-sanitize.ts +66 -0
- package/.pi/extensions/sentrux-rules-sync.ts +0 -18
- package/.pi/harness/README.md +3 -2
- package/.pi/harness/docs/adrs/0004-defer-ci-agent-smoke.md +1 -1
- package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +1 -1
- package/.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md +2 -2
- package/.pi/harness/evals/smoke/README.md +1 -1
- package/.pi/harness/evolution/README.md +1 -1
- package/.pi/harness/evolution/chaos-drill.md +1 -1
- package/.pi/prompts/harness-setup.md +42 -35
- package/.pi/scripts/README.md +25 -9
- package/.pi/scripts/harness-cli-verify.sh +4 -2
- package/.pi/scripts/harness-seed-project-contracts.mjs +49 -0
- package/.pi/scripts/harness-sync-model-router.mjs +84 -0
- package/.pi/scripts/harness-verify.mjs +5 -3
- package/.pi/scripts/sentrux-rules-sync.mjs +2 -2
- package/.pi/scripts/vendor-sync-pi-model-router.sh +47 -0
- package/.pi/settings.example.json +0 -1
- package/.sentrux/rules.toml +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +62 -0
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/biome.json +2 -1
- package/package.json +9 -10
- package/vendor/pi-model-router/.prettierignore +4 -0
- package/vendor/pi-model-router/.prettierrc +5 -0
- package/vendor/pi-model-router/AGENTS.md +39 -0
- package/vendor/pi-model-router/LICENSE +21 -0
- package/vendor/pi-model-router/README.md +99 -0
- package/vendor/pi-model-router/UPSTREAM_PIN.md +8 -0
- package/vendor/pi-model-router/docs/ARCHITECTURE.md +54 -0
- package/vendor/pi-model-router/extensions/commands.ts +720 -0
- package/vendor/pi-model-router/extensions/config.ts +348 -0
- package/vendor/pi-model-router/extensions/constants.ts +1 -0
- package/vendor/pi-model-router/extensions/index.ts +457 -0
- package/vendor/pi-model-router/extensions/provider.ts +529 -0
- package/vendor/pi-model-router/extensions/routing.ts +416 -0
- package/vendor/pi-model-router/extensions/state.ts +49 -0
- package/vendor/pi-model-router/extensions/types.ts +86 -0
- package/vendor/pi-model-router/extensions/ui.ts +130 -0
- package/vendor/pi-model-router/model-router.example.json +48 -0
- package/vendor/pi-model-router/package.json +48 -0
- package/vendor/pi-model-router/tsconfig.json +16 -0
- package/.pi/extensions/model-router-bootstrap.ts +0 -174
- package/.sentrux/.harness-rules-meta.json +0 -5
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { getAgentDir } from '@mariozechner/pi-coding-agent';
|
|
4
|
+
import type { ThinkingLevel } from '@mariozechner/pi-agent-core';
|
|
5
|
+
import type {
|
|
6
|
+
RouterConfig,
|
|
7
|
+
RouterProfile,
|
|
8
|
+
RoutedTierConfig,
|
|
9
|
+
ConfigLoadResult,
|
|
10
|
+
ParsedConfigFile,
|
|
11
|
+
RouterTier,
|
|
12
|
+
RoutingRule,
|
|
13
|
+
} from './types.js';
|
|
14
|
+
|
|
15
|
+
export const ROUTER_TIERS = ['high', 'medium', 'low'] as const;
|
|
16
|
+
|
|
17
|
+
export const FALLBACK_CONFIG: RouterConfig = {
|
|
18
|
+
defaultProfile: 'auto',
|
|
19
|
+
debug: false,
|
|
20
|
+
profiles: {
|
|
21
|
+
auto: {
|
|
22
|
+
high: { model: 'openai/gpt-5.4-pro', thinking: 'off' },
|
|
23
|
+
medium: { model: 'google/gemini-flash-latest', thinking: 'off' },
|
|
24
|
+
low: { model: 'openai/gpt-5.4-nano', thinking: 'off' },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const THINKING_LEVELS: readonly ThinkingLevel[] = [
|
|
30
|
+
'off',
|
|
31
|
+
'minimal',
|
|
32
|
+
'low',
|
|
33
|
+
'medium',
|
|
34
|
+
'high',
|
|
35
|
+
'xhigh',
|
|
36
|
+
];
|
|
37
|
+
export const ROUTER_PIN_VALUES = ['auto', 'high', 'medium', 'low'] as const;
|
|
38
|
+
|
|
39
|
+
export const isObjectRecord = (
|
|
40
|
+
value: unknown,
|
|
41
|
+
): value is Record<string, unknown> =>
|
|
42
|
+
typeof value === 'object' && value !== null;
|
|
43
|
+
|
|
44
|
+
export const isThinkingLevel = (value: unknown): value is ThinkingLevel =>
|
|
45
|
+
typeof value === 'string' && THINKING_LEVELS.includes(value as ThinkingLevel);
|
|
46
|
+
|
|
47
|
+
export const isRouterTier = (value: unknown): value is RouterTier =>
|
|
48
|
+
value === 'high' || value === 'medium' || value === 'low';
|
|
49
|
+
|
|
50
|
+
export const parseConfigFile = (path: string): ParsedConfigFile => {
|
|
51
|
+
if (!existsSync(path)) {
|
|
52
|
+
return { config: {}, warnings: [] };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
|
|
57
|
+
if (!isObjectRecord(parsed)) {
|
|
58
|
+
return {
|
|
59
|
+
config: {},
|
|
60
|
+
warnings: [`Ignored router config at ${path}: expected a JSON object.`],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return { config: parsed as Partial<RouterConfig>, warnings: [] };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
config: {},
|
|
67
|
+
warnings: [
|
|
68
|
+
`Failed to parse router config at ${path}: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const mergeConfig = (
|
|
75
|
+
base: RouterConfig,
|
|
76
|
+
override: Partial<RouterConfig>,
|
|
77
|
+
): RouterConfig => {
|
|
78
|
+
const mergedProfiles: Record<string, RouterProfile> = { ...base.profiles };
|
|
79
|
+
for (const [name, profile] of Object.entries(override.profiles ?? {})) {
|
|
80
|
+
const existing = mergedProfiles[name];
|
|
81
|
+
const nextProfile = profile as Partial<RouterProfile>;
|
|
82
|
+
mergedProfiles[name] = {
|
|
83
|
+
high: {
|
|
84
|
+
...(existing?.high ?? FALLBACK_CONFIG.profiles.auto.high),
|
|
85
|
+
...(nextProfile.high ?? {}),
|
|
86
|
+
},
|
|
87
|
+
medium: {
|
|
88
|
+
...(existing?.medium ?? FALLBACK_CONFIG.profiles.auto.medium),
|
|
89
|
+
...(nextProfile.medium ?? {}),
|
|
90
|
+
},
|
|
91
|
+
low: {
|
|
92
|
+
...(existing?.low ?? FALLBACK_CONFIG.profiles.auto.low),
|
|
93
|
+
...(nextProfile.low ?? {}),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
defaultProfile: override.defaultProfile ?? base.defaultProfile,
|
|
99
|
+
debug: override.debug ?? base.debug,
|
|
100
|
+
classifierModel: override.classifierModel ?? base.classifierModel,
|
|
101
|
+
phaseBias: override.phaseBias ?? base.phaseBias,
|
|
102
|
+
largeContextThreshold:
|
|
103
|
+
override.largeContextThreshold ?? base.largeContextThreshold,
|
|
104
|
+
maxSessionBudget: override.maxSessionBudget ?? base.maxSessionBudget,
|
|
105
|
+
rules: override.rules ?? base.rules,
|
|
106
|
+
profiles: mergedProfiles,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const parseCanonicalModelRef = (
|
|
111
|
+
value: string,
|
|
112
|
+
): { provider: string; modelId: string } => {
|
|
113
|
+
const slashIndex = value.indexOf('/');
|
|
114
|
+
if (slashIndex === -1) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`Invalid model reference "${value}". Expected "provider/model".`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const provider = value.slice(0, slashIndex).trim();
|
|
120
|
+
const modelId = value.slice(slashIndex + 1).trim();
|
|
121
|
+
if (!provider || !modelId) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`Invalid model reference "${value}". Expected "provider/model".`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return { provider, modelId };
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const normalizeTierConfig = (
|
|
130
|
+
value: unknown,
|
|
131
|
+
fallback: RoutedTierConfig,
|
|
132
|
+
profileName: string,
|
|
133
|
+
tier: RouterTier,
|
|
134
|
+
warnings: string[],
|
|
135
|
+
): RoutedTierConfig => {
|
|
136
|
+
if (!isObjectRecord(value)) {
|
|
137
|
+
warnings.push(
|
|
138
|
+
`Profile "${profileName}" has invalid ${tier} tier config. Falling back to ${fallback.model}.`,
|
|
139
|
+
);
|
|
140
|
+
return { ...fallback };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const model = typeof value.model === 'string' ? value.model.trim() : '';
|
|
144
|
+
let parsedModel = fallback.model;
|
|
145
|
+
if (!model) {
|
|
146
|
+
warnings.push(
|
|
147
|
+
`Profile "${profileName}" ${tier} tier is missing a model. Falling back to ${fallback.model}.`,
|
|
148
|
+
);
|
|
149
|
+
} else {
|
|
150
|
+
try {
|
|
151
|
+
parseCanonicalModelRef(model);
|
|
152
|
+
parsedModel = model;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
warnings.push(error instanceof Error ? error.message : String(error));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const thinking = isThinkingLevel(value.thinking)
|
|
159
|
+
? value.thinking
|
|
160
|
+
: fallback.thinking;
|
|
161
|
+
if (value.thinking !== undefined && !isThinkingLevel(value.thinking)) {
|
|
162
|
+
warnings.push(
|
|
163
|
+
`Profile "${profileName}" ${tier} tier has invalid thinking level. Falling back to ${fallback.thinking ?? 'medium'}.`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let fallbacks: string[] | undefined = undefined;
|
|
168
|
+
if (Array.isArray(value.fallbacks)) {
|
|
169
|
+
fallbacks = [];
|
|
170
|
+
for (const f of value.fallbacks) {
|
|
171
|
+
if (typeof f === 'string') {
|
|
172
|
+
try {
|
|
173
|
+
parseCanonicalModelRef(f);
|
|
174
|
+
fallbacks.push(f);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
warnings.push(
|
|
177
|
+
`Invalid fallback model "${f}" in profile "${profileName}" ${tier} tier: ${error instanceof Error ? error.message : String(error)}`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return { model: parsedModel, thinking, fallbacks };
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const normalizeConfig = (raw: RouterConfig): ConfigLoadResult => {
|
|
188
|
+
const warnings: string[] = [];
|
|
189
|
+
const normalizedProfiles: Record<string, RouterProfile> = {};
|
|
190
|
+
const fallbackAuto = FALLBACK_CONFIG.profiles.auto;
|
|
191
|
+
|
|
192
|
+
for (const [name, profile] of Object.entries(raw.profiles ?? {})) {
|
|
193
|
+
normalizedProfiles[name] = {
|
|
194
|
+
high: normalizeTierConfig(
|
|
195
|
+
profile?.high,
|
|
196
|
+
fallbackAuto.high,
|
|
197
|
+
name,
|
|
198
|
+
'high',
|
|
199
|
+
warnings,
|
|
200
|
+
),
|
|
201
|
+
medium: normalizeTierConfig(
|
|
202
|
+
profile?.medium,
|
|
203
|
+
fallbackAuto.medium,
|
|
204
|
+
name,
|
|
205
|
+
'medium',
|
|
206
|
+
warnings,
|
|
207
|
+
),
|
|
208
|
+
low: normalizeTierConfig(
|
|
209
|
+
profile?.low,
|
|
210
|
+
fallbackAuto.low,
|
|
211
|
+
name,
|
|
212
|
+
'low',
|
|
213
|
+
warnings,
|
|
214
|
+
),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (Object.keys(normalizedProfiles).length === 0) {
|
|
219
|
+
normalizedProfiles.auto = fallbackAuto;
|
|
220
|
+
warnings.push(
|
|
221
|
+
'No valid router profiles found. Falling back to the built-in auto profile.',
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let defaultProfile =
|
|
226
|
+
typeof raw.defaultProfile === 'string' && raw.defaultProfile.trim()
|
|
227
|
+
? raw.defaultProfile.trim()
|
|
228
|
+
: undefined;
|
|
229
|
+
if (!defaultProfile || !normalizedProfiles[defaultProfile]) {
|
|
230
|
+
const fallbackProfile = normalizedProfiles[
|
|
231
|
+
FALLBACK_CONFIG.defaultProfile ?? 'auto'
|
|
232
|
+
]
|
|
233
|
+
? (FALLBACK_CONFIG.defaultProfile ?? 'auto')
|
|
234
|
+
: Object.keys(normalizedProfiles).sort()[0];
|
|
235
|
+
if (defaultProfile && !normalizedProfiles[defaultProfile]) {
|
|
236
|
+
warnings.push(
|
|
237
|
+
`Default router profile "${defaultProfile}" was not found. Falling back to "${fallbackProfile}".`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
defaultProfile = fallbackProfile;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const phaseBias =
|
|
244
|
+
typeof raw.phaseBias === 'number'
|
|
245
|
+
? Math.max(0, Math.min(1, raw.phaseBias))
|
|
246
|
+
: 0.5;
|
|
247
|
+
|
|
248
|
+
const largeContextThreshold =
|
|
249
|
+
typeof raw.largeContextThreshold === 'number' &&
|
|
250
|
+
raw.largeContextThreshold > 0
|
|
251
|
+
? raw.largeContextThreshold
|
|
252
|
+
: undefined;
|
|
253
|
+
|
|
254
|
+
const maxSessionBudget =
|
|
255
|
+
typeof raw.maxSessionBudget === 'number' && raw.maxSessionBudget > 0
|
|
256
|
+
? raw.maxSessionBudget
|
|
257
|
+
: undefined;
|
|
258
|
+
|
|
259
|
+
const rules: RoutingRule[] = [];
|
|
260
|
+
if (Array.isArray(raw.rules)) {
|
|
261
|
+
for (const rule of raw.rules) {
|
|
262
|
+
if (isObjectRecord(rule)) {
|
|
263
|
+
const matches = rule.matches;
|
|
264
|
+
const tier = rule.tier;
|
|
265
|
+
if (
|
|
266
|
+
(typeof matches === 'string' || Array.isArray(matches)) &&
|
|
267
|
+
isRouterTier(tier)
|
|
268
|
+
) {
|
|
269
|
+
rules.push({
|
|
270
|
+
matches,
|
|
271
|
+
tier,
|
|
272
|
+
reason: typeof rule.reason === 'string' ? rule.reason : undefined,
|
|
273
|
+
});
|
|
274
|
+
} else {
|
|
275
|
+
warnings.push(
|
|
276
|
+
`Ignored invalid routing rule: ${JSON.stringify(rule)}`,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let classifierModel =
|
|
284
|
+
typeof raw.classifierModel === 'string'
|
|
285
|
+
? raw.classifierModel.trim()
|
|
286
|
+
: undefined;
|
|
287
|
+
if (classifierModel) {
|
|
288
|
+
try {
|
|
289
|
+
parseCanonicalModelRef(classifierModel);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
warnings.push(
|
|
292
|
+
`Invalid classifierModel: ${error instanceof Error ? error.message : String(error)}`,
|
|
293
|
+
);
|
|
294
|
+
classifierModel = undefined;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
config: {
|
|
300
|
+
defaultProfile,
|
|
301
|
+
debug: typeof raw.debug === 'boolean' ? raw.debug : false,
|
|
302
|
+
classifierModel,
|
|
303
|
+
phaseBias,
|
|
304
|
+
largeContextThreshold,
|
|
305
|
+
maxSessionBudget,
|
|
306
|
+
rules: rules.length > 0 ? rules : undefined,
|
|
307
|
+
profiles: normalizedProfiles,
|
|
308
|
+
},
|
|
309
|
+
warnings,
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
export const loadRouterConfig = (cwd: string): ConfigLoadResult => {
|
|
314
|
+
const globalPath = join(getAgentDir(), 'model-router.json');
|
|
315
|
+
const projectPath = join(cwd, '.pi', 'model-router.json');
|
|
316
|
+
const globalResult = parseConfigFile(globalPath);
|
|
317
|
+
const projectResult = parseConfigFile(projectPath);
|
|
318
|
+
const merged = mergeConfig(
|
|
319
|
+
mergeConfig(FALLBACK_CONFIG, globalResult.config),
|
|
320
|
+
projectResult.config,
|
|
321
|
+
);
|
|
322
|
+
const normalized = normalizeConfig(merged);
|
|
323
|
+
return {
|
|
324
|
+
config: normalized.config,
|
|
325
|
+
warnings: [
|
|
326
|
+
...globalResult.warnings,
|
|
327
|
+
...projectResult.warnings,
|
|
328
|
+
...normalized.warnings,
|
|
329
|
+
],
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
export const profileNames = (config: RouterConfig): string[] => {
|
|
334
|
+
return Object.keys(config.profiles).sort();
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
export const resolveProfileName = (
|
|
338
|
+
config: RouterConfig,
|
|
339
|
+
requested?: string,
|
|
340
|
+
): string => {
|
|
341
|
+
if (requested && config.profiles[requested]) {
|
|
342
|
+
return requested;
|
|
343
|
+
}
|
|
344
|
+
if (config.defaultProfile && config.profiles[config.defaultProfile]) {
|
|
345
|
+
return config.defaultProfile;
|
|
346
|
+
}
|
|
347
|
+
return profileNames(config)[0] ?? 'auto';
|
|
348
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const MAX_DEBUG_HISTORY = 12;
|