Files
hapi/web/src/components/AssistantChat/piThinkingLevelOptions.ts
T
KorenKritaandGitHub 3290bc9ca9 feat(pi): add 'max' thinking level (#1032)
* feat(pi): add 'max' thinking level

Pi's --thinking flag accepts 7 levels: off, minimal, low, medium, high,
xhigh, max. The shared constant and UI only exposed 6 levels (missing max).

Add 'max' to PI_THINKING_LEVELS and PI_THINKING_LEVEL_LABELS. Like xhigh,
max requires explicit opt-in via the model's thinkingLevelMap — models that
support it will include max in their map and the UI will show it
accordingly.

* fix(pi): close max thinking-level branch
2026-07-16 12:30:55 +08:00

84 lines
2.8 KiB
TypeScript

import { PI_THINKING_LEVELS, PI_THINKING_LEVEL_LABELS, type PiThinkingLevel } from '@hapi/protocol'
import type { PiThinkingLevelMap } from '@/types/api'
type PiThinkingLevelOption = {
value: string
label: string
}
function normalizePiThinkingLevel(level?: string | null): string | null {
const trimmedLevel = level?.trim().toLowerCase()
if (!trimmedLevel || trimmedLevel === 'default' || trimmedLevel === 'auto') {
return null
}
return trimmedLevel
}
function formatPiThinkingLevelLabel(level: string): string {
return PI_THINKING_LEVEL_LABELS[level as PiThinkingLevel]
?? `${level.charAt(0).toUpperCase()}${level.slice(1)}`
}
/**
* Get thinking level options filtered by the model's thinkingLevelMap.
* Levels mapped to `null` in the map are unsupported and excluded.
* Levels not present in the map are included (treated as supported with default mapping).
*/
export function getPiThinkingLevelOptions(
currentLevel?: string | null,
thinkingLevelMap?: PiThinkingLevelMap
): PiThinkingLevelOption[] {
const normalizedCurrentLevel = normalizePiThinkingLevel(currentLevel)
const options: PiThinkingLevelOption[] = []
// Include current level if it's non-standard (custom)
if (
normalizedCurrentLevel
&& !(PI_THINKING_LEVELS as readonly string[]).includes(normalizedCurrentLevel)
&& !isLevelExcluded(normalizedCurrentLevel, thinkingLevelMap)
) {
options.push({
value: normalizedCurrentLevel,
label: formatPiThinkingLevelLabel(normalizedCurrentLevel)
})
}
options.push(...PI_THINKING_LEVELS
.filter((level) => !isLevelExcluded(level, thinkingLevelMap))
.map((level) => ({
value: level,
label: PI_THINKING_LEVEL_LABELS[level]
}))
)
return options
}
/** Check whether a thinking level is supported by the model's thinkingLevelMap */
export function isThinkingLevelSupported(level: string, map?: PiThinkingLevelMap): boolean {
// xhigh and max require explicit opt-in via the map
if (level === 'xhigh' || level === 'max') {
if (!map || !(level in map)) return false
return map[level] !== null
}
if (!map || !(level in map)) return true
return map[level] !== null
}
/** A level is excluded if it maps to `null` in the thinkingLevelMap, or xhigh/max without explicit opt-in */
function isLevelExcluded(level: string, map?: PiThinkingLevelMap): boolean {
return !isThinkingLevelSupported(level, map)
}
/** Return the highest supported thinking level, or null if none */
export function getHighestThinkingLevel(map?: PiThinkingLevelMap): string | null {
for (let i = PI_THINKING_LEVELS.length - 1; i >= 0; i--) {
if (isThinkingLevelSupported(PI_THINKING_LEVELS[i]!, map)) {
return PI_THINKING_LEVELS[i]!
}
}
return null
}