add claude code model selection (opus, sonnet, haiku)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 20:58:31 +00:00
co-authored by Claude Opus 4.6
parent c972553f22
commit d5fd3f58b1
4 changed files with 23 additions and 17 deletions
+10 -14
View File
@@ -2,15 +2,11 @@ import type { ModelInfo } from './types';
import { PI_CONFIG_DIR } from '../../data-path'; import { PI_CONFIG_DIR } from '../../data-path';
import { logger } from './logger'; import { logger } from './logger';
const CLAUDE_CODE_MODEL: ModelInfo = { const CLAUDE_CODE_MODELS: ModelInfo[] = [
id: 'claude-code', { id: 'claude-code/opus', name: 'opus', provider: 'claude-code', contextWindow: 200000, maxTokens: 16000, reasoning: true, images: true },
name: 'claude-code', { id: 'claude-code/sonnet', name: 'sonnet', provider: 'claude-code', contextWindow: 200000, maxTokens: 16000, reasoning: true, images: true },
provider: 'claude-code', { id: 'claude-code/haiku', name: 'haiku', provider: 'claude-code', contextWindow: 200000, maxTokens: 8192, reasoning: false, images: true },
contextWindow: 200000, ];
maxTokens: 16000,
reasoning: true,
images: true,
};
const CACHE_TTL_MS = 60_000; const CACHE_TTL_MS = 60_000;
@@ -36,7 +32,7 @@ const parseSize = (s?: string): number => {
export async function listPiModels(): Promise<ModelInfo[]> { export async function listPiModels(): Promise<ModelInfo[]> {
if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL_MS) { if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL_MS) {
return [...cachedModels, CLAUDE_CODE_MODEL]; return [...cachedModels, ...CLAUDE_CODE_MODELS];
} }
try { try {
@@ -59,11 +55,11 @@ export async function listPiModels(): Promise<ModelInfo[]> {
if (proc.exitCode !== 0) { if (proc.exitCode !== 0) {
const stderrText = proc.stderr.toString(); const stderrText = proc.stderr.toString();
logger.error('pi --list-models failed', { exitCode: proc.exitCode, stderr: stderrText.trim(), piBin }); logger.error('pi --list-models failed', { exitCode: proc.exitCode, stderr: stderrText.trim(), piBin });
return [CLAUDE_CODE_MODEL]; return [...CLAUDE_CODE_MODELS];
} }
const lines = output.trim().split('\n'); const lines = output.trim().split('\n');
if (lines.length < 2) return [CLAUDE_CODE_MODEL]; if (lines.length < 2) return [...CLAUDE_CODE_MODELS];
// Parse fixed-width table: provider, model, context, max-out, thinking, images // Parse fixed-width table: provider, model, context, max-out, thinking, images
const header = lines[0]!; const header = lines[0]!;
@@ -114,9 +110,9 @@ export async function listPiModels(): Promise<ModelInfo[]> {
logger.info('pi --list-models returned', { count: models.length }); logger.info('pi --list-models returned', { count: models.length });
cachedModels = models; cachedModels = models;
cacheTimestamp = Date.now(); cacheTimestamp = Date.now();
return [...models, CLAUDE_CODE_MODEL]; return [...models, ...CLAUDE_CODE_MODELS];
} catch (err) { } catch (err) {
logger.error('Failed to run pi --list-models', { error: String(err) }); logger.error('Failed to run pi --list-models', { error: String(err) });
return [CLAUDE_CODE_MODEL]; return [...CLAUDE_CODE_MODELS];
} }
} }
+3 -2
View File
@@ -275,7 +275,7 @@ async function handleChat(
userDefault, userDefault,
}); });
if (model === 'claude-code') { if (model.startsWith('claude-code')) {
return handleClaudeCodeChat(ws, sessionId, model, msg); return handleClaudeCodeChat(ws, sessionId, model, msg);
} }
@@ -424,6 +424,7 @@ async function handleClaudeCodeChat(
prompt: msg.prompt, prompt: msg.prompt,
sessionKey: sessionId, sessionKey: sessionId,
cwd, cwd,
model,
onEvent, onEvent,
}); });
@@ -553,7 +554,7 @@ async function handleStop(ws: ServerWebSocket<WSData>): Promise<void> {
if (session?.piProcess) { if (session?.piProcess) {
try { try {
if (session.model === 'claude-code') { if (session.model.startsWith('claude-code')) {
// Claude Code: kill the process directly // Claude Code: kill the process directly
session.piProcess.kill(); session.piProcess.kill();
logger.info('Killed Claude Code process', { sessionId }); logger.info('Killed Claude Code process', { sessionId });
+2 -1
View File
@@ -104,13 +104,14 @@ export async function sendAndAwait(params: SendAndAwaitParams): Promise<SendAndA
const override = channelModelOverrides.get(sessionId); const override = channelModelOverrides.get(sessionId);
const resolvedModel = params.model ?? override ?? (await getUserDefaultModel(params.userId)) ?? DEFAULT_MODEL; const resolvedModel = params.model ?? override ?? (await getUserDefaultModel(params.userId)) ?? DEFAULT_MODEL;
if (resolvedModel === 'claude-code') { if (resolvedModel.startsWith('claude-code')) {
return await sendClaudeCode({ return await sendClaudeCode({
userId: params.userId, userId: params.userId,
email: params.email, email: params.email,
username: params.username, username: params.username,
prompt: params.prompt, prompt: params.prompt,
sessionKey: sessionId, sessionKey: sessionId,
model: resolvedModel,
}); });
} }
+8
View File
@@ -31,6 +31,7 @@ type ClaudeCodeParams = {
username: string; username: string;
prompt: string; prompt: string;
sessionKey: string; sessionKey: string;
model?: string;
}; };
type ClaudeCodeResult = { type ClaudeCodeResult = {
@@ -151,6 +152,9 @@ export async function sendClaudeCode(params: ClaudeCodeParams): Promise<ClaudeCo
const claudeArgs = [CLAUDE_BIN, '-p', prompt, '--dangerously-skip-permissions', '--output-format', 'json']; const claudeArgs = [CLAUDE_BIN, '-p', prompt, '--dangerously-skip-permissions', '--output-format', 'json'];
const subModel = params.model?.split('/')[1];
if (subModel) claudeArgs.push('--model', subModel);
const existingSession = claudeCodeSessions.get(sessionKey); const existingSession = claudeCodeSessions.get(sessionKey);
if (existingSession) { if (existingSession) {
claudeArgs.push('--resume', existingSession); claudeArgs.push('--resume', existingSession);
@@ -268,6 +272,7 @@ type ClaudeCodeStreamingParams = {
prompt: string; prompt: string;
sessionKey: string; sessionKey: string;
cwd?: string; cwd?: string;
model?: string;
onEvent: (event: PiEvent) => void; onEvent: (event: PiEvent) => void;
}; };
@@ -293,6 +298,9 @@ export async function sendClaudeCodeStreaming(params: ClaudeCodeStreamingParams)
'--include-partial-messages', '--include-partial-messages',
]; ];
const subModel = params.model?.split('/')[1];
if (subModel) claudeArgs.push('--model', subModel);
const existingSession = claudeCodeSessions.get(sessionKey); const existingSession = claudeCodeSessions.get(sessionKey);
if (existingSession) { if (existingSession) {
claudeArgs.push('--resume', existingSession); claudeArgs.push('--resume', existingSession);