mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
remove , using instead
This commit is contained in:
@@ -6,9 +6,8 @@ import { Session } from "./session"
|
||||
import { claudeLocalLauncher } from "./claudeLocalLauncher"
|
||||
import { claudeRemoteLauncher } from "./claudeRemoteLauncher"
|
||||
import { ApiClient } from "@/lib"
|
||||
import type { SessionModelMode } from "@/api/types"
|
||||
import type { SessionModel } from "@/api/types"
|
||||
import type { ClaudePermissionMode } from "@hapi/protocol/types"
|
||||
import { resolveClaudeSessionModelMode } from "./modelMode"
|
||||
|
||||
export type PermissionMode = ClaudePermissionMode;
|
||||
|
||||
@@ -24,7 +23,7 @@ export interface EnhancedMode {
|
||||
|
||||
interface LoopOptions {
|
||||
path: string
|
||||
model?: string
|
||||
model?: SessionModel
|
||||
permissionMode?: PermissionMode
|
||||
startingMode?: 'local' | 'remote'
|
||||
startedBy?: 'runner' | 'terminal'
|
||||
@@ -46,7 +45,6 @@ export async function loop(opts: LoopOptions) {
|
||||
const logPath = logger.logFilePath;
|
||||
const startedBy = opts.startedBy ?? 'terminal';
|
||||
const startingMode = opts.startingMode ?? 'local';
|
||||
const modelMode: SessionModelMode = resolveClaudeSessionModelMode(opts.model)
|
||||
const session = new Session({
|
||||
api: opts.api,
|
||||
client: opts.session,
|
||||
@@ -64,7 +62,7 @@ export async function loop(opts: LoopOptions) {
|
||||
startingMode,
|
||||
hookSettingsPath: opts.hookSettingsPath,
|
||||
permissionMode: opts.permissionMode ?? 'default',
|
||||
modelMode
|
||||
model: opts.model
|
||||
});
|
||||
|
||||
await runLocalRemoteSession({
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { normalizeClaudeSessionModel } from './model'
|
||||
|
||||
describe('normalizeClaudeSessionModel', () => {
|
||||
it('returns null when model is missing', () => {
|
||||
expect(normalizeClaudeSessionModel()).toBeNull()
|
||||
})
|
||||
|
||||
it('returns null for auto-like values', () => {
|
||||
expect(normalizeClaudeSessionModel('')).toBeNull()
|
||||
expect(normalizeClaudeSessionModel('auto')).toBeNull()
|
||||
expect(normalizeClaudeSessionModel('default')).toBeNull()
|
||||
})
|
||||
|
||||
it('preserves Claude aliases and full model strings', () => {
|
||||
expect(normalizeClaudeSessionModel('sonnet')).toBe('sonnet')
|
||||
expect(normalizeClaudeSessionModel('opus[1m]')).toBe('opus[1m]')
|
||||
expect(normalizeClaudeSessionModel('claude-3-7-sonnet-latest')).toBe('claude-3-7-sonnet-latest')
|
||||
expect(normalizeClaudeSessionModel(' claude-opus-4-1-20250805 ')).toBe('claude-opus-4-1-20250805')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { SessionModel } from '@/api/types'
|
||||
|
||||
export function normalizeClaudeSessionModel(model?: string | null): SessionModel {
|
||||
const trimmedModel = model?.trim()
|
||||
if (!trimmedModel || trimmedModel === 'auto' || trimmedModel === 'default') {
|
||||
return null
|
||||
}
|
||||
|
||||
return trimmedModel
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { resolveClaudePersistedModel, resolveClaudeSessionModelMode } from './modelMode'
|
||||
|
||||
describe('resolveClaudeSessionModelMode', () => {
|
||||
it('returns default when model is missing', () => {
|
||||
expect(resolveClaudeSessionModelMode()).toBe('default')
|
||||
})
|
||||
|
||||
it('returns default for auto and unsupported models', () => {
|
||||
expect(resolveClaudeSessionModelMode('auto')).toBe('default')
|
||||
expect(resolveClaudeSessionModelMode('claude-sonnet-4-5')).toBe('default')
|
||||
})
|
||||
|
||||
it('returns standard Claude session model modes', () => {
|
||||
expect(resolveClaudeSessionModelMode('sonnet')).toBe('sonnet')
|
||||
expect(resolveClaudeSessionModelMode('opus')).toBe('opus')
|
||||
})
|
||||
|
||||
it('returns 1m Claude session model modes', () => {
|
||||
expect(resolveClaudeSessionModelMode('sonnet[1m]')).toBe('sonnet[1m]')
|
||||
expect(resolveClaudeSessionModelMode('opus[1m]')).toBe('opus[1m]')
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveClaudePersistedModel', () => {
|
||||
it('skips missing, auto, default, and representable mode names', () => {
|
||||
expect(resolveClaudePersistedModel()).toBeUndefined()
|
||||
expect(resolveClaudePersistedModel('')).toBeUndefined()
|
||||
expect(resolveClaudePersistedModel('auto')).toBeUndefined()
|
||||
expect(resolveClaudePersistedModel('default')).toBeUndefined()
|
||||
expect(resolveClaudePersistedModel('sonnet')).toBeUndefined()
|
||||
expect(resolveClaudePersistedModel('opus[1m]')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('persists unsupported custom Claude model strings', () => {
|
||||
expect(resolveClaudePersistedModel('claude-3-7-sonnet-latest')).toBe('claude-3-7-sonnet-latest')
|
||||
expect(resolveClaudePersistedModel(' claude-opus-4-1-20250805 ')).toBe('claude-opus-4-1-20250805')
|
||||
})
|
||||
})
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { SessionModelMode } from '@/api/types'
|
||||
|
||||
const CLAUDE_SESSION_MODEL_MODES = new Set<SessionModelMode>([
|
||||
'sonnet',
|
||||
'sonnet[1m]',
|
||||
'opus',
|
||||
'opus[1m]'
|
||||
])
|
||||
|
||||
export function resolveClaudeSessionModelMode(model?: string): SessionModelMode {
|
||||
const trimmedModel = model?.trim()
|
||||
if (!trimmedModel) {
|
||||
return 'default'
|
||||
}
|
||||
|
||||
return CLAUDE_SESSION_MODEL_MODES.has(trimmedModel as SessionModelMode)
|
||||
? trimmedModel as SessionModelMode
|
||||
: 'default'
|
||||
}
|
||||
|
||||
export function resolveClaudePersistedModel(model?: string): string | undefined {
|
||||
const trimmedModel = model?.trim()
|
||||
if (!trimmedModel || trimmedModel === 'auto' || trimmedModel === 'default') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return resolveClaudeSessionModelMode(trimmedModel) === 'default'
|
||||
? trimmedModel
|
||||
: undefined
|
||||
}
|
||||
+29
-21
@@ -1,6 +1,6 @@
|
||||
import { logger } from '@/ui/logger';
|
||||
import { loop } from '@/claude/loop';
|
||||
import { AgentState, SessionModelMode } from '@/api/types';
|
||||
import { AgentState, SessionModel } from '@/api/types';
|
||||
import { EnhancedMode, PermissionMode } from './loop';
|
||||
import { MessageQueue2 } from '@/utils/MessageQueue2';
|
||||
import { hashObject } from '@/utils/deterministicJson';
|
||||
@@ -14,10 +14,10 @@ import { registerKillSessionHandler } from './registerKillSessionHandler';
|
||||
import type { Session } from './session';
|
||||
import { bootstrapSession } from '@/agent/sessionFactory';
|
||||
import { createModeChangeHandler, createRunnerLifecycle, setControlledByUser } from '@/agent/runnerLifecycle';
|
||||
import { isModelModeAllowedForFlavor, isPermissionModeAllowedForFlavor } from '@hapi/protocol';
|
||||
import { ModelModeSchema, PermissionModeSchema } from '@hapi/protocol/schemas';
|
||||
import { isPermissionModeAllowedForFlavor } from '@hapi/protocol';
|
||||
import { PermissionModeSchema } from '@hapi/protocol/schemas';
|
||||
import { formatMessageWithAttachments } from '@/utils/attachmentFormatter';
|
||||
import { resolveClaudePersistedModel, resolveClaudeSessionModelMode } from './modelMode';
|
||||
import { normalizeClaudeSessionModel } from './model';
|
||||
|
||||
export interface StartOptions {
|
||||
model?: string
|
||||
@@ -46,12 +46,13 @@ export async function runClaude(options: StartOptions = {}): Promise<void> {
|
||||
}
|
||||
|
||||
const initialState: AgentState = {};
|
||||
const initialModel = normalizeClaudeSessionModel(options.model);
|
||||
const { api, session, sessionInfo } = await bootstrapSession({
|
||||
flavor: 'claude',
|
||||
startedBy,
|
||||
workingDirectory,
|
||||
agentState: initialState,
|
||||
model: resolveClaudePersistedModel(options.model)
|
||||
model: initialModel ?? undefined
|
||||
});
|
||||
logger.debug(`Session created: ${sessionInfo.id}`);
|
||||
|
||||
@@ -145,7 +146,7 @@ export async function runClaude(options: StartOptions = {}): Promise<void> {
|
||||
|
||||
// Forward messages to the queue
|
||||
let currentPermissionMode: PermissionMode = options.permissionMode ?? 'default';
|
||||
let currentModelMode: SessionModelMode = resolveClaudeSessionModelMode(options.model);
|
||||
let currentModel: SessionModel = initialModel;
|
||||
let currentFallbackModel: string | undefined = undefined; // Track current fallback model
|
||||
let currentCustomSystemPrompt: string | undefined = undefined; // Track current custom system prompt
|
||||
let currentAppendSystemPrompt: string | undefined = undefined; // Track current append system prompt
|
||||
@@ -158,17 +159,21 @@ export async function runClaude(options: StartOptions = {}): Promise<void> {
|
||||
return;
|
||||
}
|
||||
sessionInstance.setPermissionMode(currentPermissionMode);
|
||||
sessionInstance.setModelMode(currentModelMode);
|
||||
logger.debug(`[loop] Synced session modes for keepalive: permissionMode=${currentPermissionMode}, modelMode=${currentModelMode}`);
|
||||
sessionInstance.setModel(currentModel);
|
||||
logger.debug(`[loop] Synced session config for keepalive: permissionMode=${currentPermissionMode}, model=${currentModel ?? 'auto'}`);
|
||||
};
|
||||
session.onUserMessage((message) => {
|
||||
const sessionPermissionMode = currentSessionRef.current?.getPermissionMode();
|
||||
if (sessionPermissionMode && isPermissionModeAllowedForFlavor(sessionPermissionMode, 'claude')) {
|
||||
currentPermissionMode = sessionPermissionMode as PermissionMode;
|
||||
}
|
||||
const sessionModel = currentSessionRef.current?.getModel();
|
||||
if (sessionModel !== undefined) {
|
||||
currentModel = sessionModel;
|
||||
}
|
||||
const messagePermissionMode = currentPermissionMode;
|
||||
const messageModel = currentModelMode === 'default' ? undefined : currentModelMode;
|
||||
logger.debug(`[loop] User message received with permission mode: ${currentPermissionMode}, model: ${currentModelMode}`);
|
||||
const messageModel = currentModel ?? undefined;
|
||||
logger.debug(`[loop] User message received with permission mode: ${currentPermissionMode}, model: ${currentModel ?? 'auto'}`);
|
||||
|
||||
// Resolve custom system prompt - use message.meta.customSystemPrompt if provided, otherwise use current
|
||||
let messageCustomSystemPrompt = currentCustomSystemPrompt;
|
||||
@@ -284,31 +289,34 @@ export async function runClaude(options: StartOptions = {}): Promise<void> {
|
||||
return parsed.data as PermissionMode;
|
||||
};
|
||||
|
||||
const resolveModelMode = (value: unknown): SessionModelMode => {
|
||||
const parsed = ModelModeSchema.safeParse(value);
|
||||
if (!parsed.success || !isModelModeAllowedForFlavor(parsed.data, 'claude')) {
|
||||
throw new Error('Invalid model mode');
|
||||
const resolveModel = (value: unknown): SessionModel => {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return parsed.data;
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error('Invalid model');
|
||||
}
|
||||
|
||||
return normalizeClaudeSessionModel(value);
|
||||
};
|
||||
|
||||
session.rpcHandlerManager.registerHandler('set-session-config', async (payload: unknown) => {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
throw new Error('Invalid session config payload');
|
||||
}
|
||||
const config = payload as { permissionMode?: unknown; modelMode?: unknown };
|
||||
const config = payload as { permissionMode?: unknown; model?: unknown };
|
||||
|
||||
if (config.permissionMode !== undefined) {
|
||||
currentPermissionMode = resolvePermissionMode(config.permissionMode);
|
||||
}
|
||||
|
||||
if (config.modelMode !== undefined) {
|
||||
const resolvedModelMode = resolveModelMode(config.modelMode);
|
||||
currentModelMode = resolvedModelMode;
|
||||
if (config.model !== undefined) {
|
||||
currentModel = resolveModel(config.model);
|
||||
}
|
||||
|
||||
syncSessionModes();
|
||||
return { applied: { permissionMode: currentPermissionMode, modelMode: currentModelMode } };
|
||||
return { applied: { permissionMode: currentPermissionMode, model: currentModel } };
|
||||
});
|
||||
|
||||
let loopError: unknown = null;
|
||||
@@ -316,7 +324,7 @@ export async function runClaude(options: StartOptions = {}): Promise<void> {
|
||||
try {
|
||||
await loop({
|
||||
path: workingDirectory,
|
||||
model: options.model,
|
||||
model: currentModel,
|
||||
permissionMode: options.permissionMode,
|
||||
startingMode,
|
||||
messageQueue,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApiClient, ApiSessionClient } from '@/lib';
|
||||
import { MessageQueue2 } from '@/utils/MessageQueue2';
|
||||
import { logger } from '@/ui/logger';
|
||||
import { AgentSessionBase } from '@/agent/sessionBase';
|
||||
import type { SessionModelMode } from '@/api/types';
|
||||
import type { SessionModel } from '@/api/types';
|
||||
import type { EnhancedMode } from './loop';
|
||||
import type { PermissionMode } from './loop';
|
||||
import type { LocalLaunchExitReason } from '@/agent/localLaunchPolicy';
|
||||
@@ -39,7 +39,7 @@ export class Session extends AgentSessionBase<EnhancedMode> {
|
||||
startingMode: 'local' | 'remote';
|
||||
hookSettingsPath: string;
|
||||
permissionMode?: PermissionMode;
|
||||
modelMode?: SessionModelMode;
|
||||
model?: SessionModel;
|
||||
}) {
|
||||
super({
|
||||
api: opts.api,
|
||||
@@ -57,7 +57,7 @@ export class Session extends AgentSessionBase<EnhancedMode> {
|
||||
claudeSessionId: sessionId
|
||||
}),
|
||||
permissionMode: opts.permissionMode,
|
||||
modelMode: opts.modelMode
|
||||
model: opts.model
|
||||
});
|
||||
|
||||
this.claudeEnvVars = opts.claudeEnvVars;
|
||||
@@ -68,15 +68,15 @@ export class Session extends AgentSessionBase<EnhancedMode> {
|
||||
this.startedBy = opts.startedBy;
|
||||
this.startingMode = opts.startingMode;
|
||||
this.permissionMode = opts.permissionMode;
|
||||
this.modelMode = opts.modelMode;
|
||||
this.model = opts.model;
|
||||
}
|
||||
|
||||
setPermissionMode = (mode: PermissionMode): void => {
|
||||
this.permissionMode = mode;
|
||||
};
|
||||
|
||||
setModelMode = (mode: SessionModelMode): void => {
|
||||
this.modelMode = mode;
|
||||
setModel = (model: SessionModel): void => {
|
||||
this.model = model;
|
||||
};
|
||||
|
||||
recordLocalLaunchFailure = (message: string, exitReason: LocalLaunchExitReason): void => {
|
||||
|
||||
Reference in New Issue
Block a user