add claude code model selection (opus, sonnet, haiku)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user