mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
Merge branch 'codex/investigate-desktop-first-token-latency'
This commit is contained in:
commit
c69c07fcfe
@ -39,7 +39,7 @@ type SettingsStore = {
|
|||||||
export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
||||||
permissionMode: 'default',
|
permissionMode: 'default',
|
||||||
currentModel: null,
|
currentModel: null,
|
||||||
effortLevel: 'high',
|
effortLevel: 'medium',
|
||||||
availableModels: [],
|
availableModels: [],
|
||||||
activeProviderName: null,
|
activeProviderName: null,
|
||||||
locale: getStoredLocale(),
|
locale: getStoredLocale(),
|
||||||
|
|||||||
22
src/main.tsx
22
src/main.tsx
@ -2723,16 +2723,30 @@ async function run(): Promise<CommanderCommand> {
|
|||||||
}));
|
}));
|
||||||
}, configs).catch(err => logForDebugging(`[MCP] ${label} connect error: ${err}`));
|
}, configs).catch(err => logForDebugging(`[MCP] ${label} connect error: ${err}`));
|
||||||
};
|
};
|
||||||
// Await all MCP configs — print mode is often single-turn, so
|
// Await all MCP configs for regular print-mode sessions — they're
|
||||||
// "late-connecting servers visible next turn" doesn't help. SDK init
|
// often single-turn, so "late-connecting servers visible next turn"
|
||||||
// message and turn-1 tool list both need configured MCP tools present.
|
// doesn't help. SDK init message and turn-1 tool list should include
|
||||||
|
// configured MCP tools when running plain `claude -p`.
|
||||||
|
//
|
||||||
|
// Desktop/bridge sessions (`--sdk-url`) are different: the user is
|
||||||
|
// waiting on the first visible assistant token, not a fully populated
|
||||||
|
// MCP inventory. Blocking startup on slow or failing MCP servers (for
|
||||||
|
// example a local `chatlog` HTTP endpoint timing out) makes the whole
|
||||||
|
// chat feel frozen before the first word appears. In that mode we still
|
||||||
|
// kick off the connections immediately, but let them settle in the
|
||||||
|
// background so headlessStore picks them up after the session starts.
|
||||||
|
//
|
||||||
// Zero-server case is free via the early return in connectMcpBatch.
|
// Zero-server case is free via the early return in connectMcpBatch.
|
||||||
// Connectors parallelize inside getMcpToolsCommandsAndResources
|
// Connectors parallelize inside getMcpToolsCommandsAndResources
|
||||||
// (processBatched with Promise.all). claude.ai is awaited too — its
|
// (processBatched with Promise.all). claude.ai is awaited too — its
|
||||||
// fetch was kicked off early (line ~2558) so only residual time blocks
|
// fetch was kicked off early (line ~2558) so only residual time blocks
|
||||||
// here. --bare skips claude.ai entirely for perf-sensitive scripts.
|
// here. --bare skips claude.ai entirely for perf-sensitive scripts.
|
||||||
profileCheckpoint('before_connectMcp');
|
profileCheckpoint('before_connectMcp');
|
||||||
await connectMcpBatch(regularMcpConfigs, 'regular');
|
if (sdkUrl) {
|
||||||
|
void connectMcpBatch(regularMcpConfigs, 'regular');
|
||||||
|
} else {
|
||||||
|
await connectMcpBatch(regularMcpConfigs, 'regular');
|
||||||
|
}
|
||||||
profileCheckpoint('after_connectMcp');
|
profileCheckpoint('after_connectMcp');
|
||||||
// Dedup: suppress plugin MCP servers that duplicate a claude.ai
|
// Dedup: suppress plugin MCP servers that duplicate a claude.ai
|
||||||
// connector (connector wins), then connect claude.ai servers.
|
// connector (connector wins), then connect claude.ai servers.
|
||||||
|
|||||||
@ -170,4 +170,18 @@ describe('ConversationService', () => {
|
|||||||
expect(args[0]).toContain(path.join('bin', 'claude-haha'))
|
expect(args[0]).toContain(path.join('bin', 'claude-haha'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('buildSessionCliArgs enables partial assistant messages for desktop streaming', () => {
|
||||||
|
const service = new ConversationService() as any
|
||||||
|
const args = service.buildSessionCliArgs(
|
||||||
|
'123e4567-e89b-12d3-a456-426614174000',
|
||||||
|
'ws://127.0.0.1:3456/sdk/test-session?token=test-token',
|
||||||
|
false,
|
||||||
|
{ permissionMode: 'bypassPermissions' },
|
||||||
|
) as string[]
|
||||||
|
|
||||||
|
expect(args).toContain('--include-partial-messages')
|
||||||
|
expect(args).toContain('--sdk-url')
|
||||||
|
expect(args).toContain('--replay-user-messages')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -38,7 +38,7 @@ const DEFAULT_MODELS = [
|
|||||||
const EFFORT_LEVELS = ['low', 'medium', 'high', 'max'] as const
|
const EFFORT_LEVELS = ['low', 'medium', 'high', 'max'] as const
|
||||||
|
|
||||||
const DEFAULT_MODEL = 'claude-opus-4-7'
|
const DEFAULT_MODEL = 'claude-opus-4-7'
|
||||||
const DEFAULT_EFFORT = 'max'
|
const DEFAULT_EFFORT = 'medium'
|
||||||
|
|
||||||
const settingsService = new SettingsService()
|
const settingsService = new SettingsService()
|
||||||
const providerService = new ProviderService()
|
const providerService = new ProviderService()
|
||||||
|
|||||||
@ -64,6 +64,33 @@ export class ConversationStartupError extends Error {
|
|||||||
export class ConversationService {
|
export class ConversationService {
|
||||||
private sessions = new Map<string, SessionProcess>()
|
private sessions = new Map<string, SessionProcess>()
|
||||||
|
|
||||||
|
private buildSessionCliArgs(
|
||||||
|
sessionId: string,
|
||||||
|
sdkUrl: string,
|
||||||
|
shouldResume: boolean,
|
||||||
|
options?: SessionStartOptions,
|
||||||
|
): string[] {
|
||||||
|
const dangerousMode = process.env.CLAUDE_DANGEROUS_MODE === '1'
|
||||||
|
return this.resolveCliArgs([
|
||||||
|
'--print',
|
||||||
|
'--verbose',
|
||||||
|
'--sdk-url',
|
||||||
|
sdkUrl,
|
||||||
|
'--enable-auth-status',
|
||||||
|
'--input-format',
|
||||||
|
'stream-json',
|
||||||
|
'--output-format',
|
||||||
|
'stream-json',
|
||||||
|
// Desktop chat depends on partial assistant deltas; without this the
|
||||||
|
// server only sees the completed assistant message at turn end.
|
||||||
|
'--include-partial-messages',
|
||||||
|
...(shouldResume ? ['--resume', sessionId] : ['--session-id', sessionId]),
|
||||||
|
'--replay-user-messages',
|
||||||
|
...this.getRuntimeArgs(options),
|
||||||
|
...this.getPermissionArgs(options?.permissionMode, dangerousMode),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
async startSession(
|
async startSession(
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
workDir: string,
|
workDir: string,
|
||||||
@ -88,22 +115,12 @@ export class ConversationService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const dangerousMode = process.env.CLAUDE_DANGEROUS_MODE === '1'
|
const args = this.buildSessionCliArgs(
|
||||||
const args = this.resolveCliArgs([
|
sessionId,
|
||||||
'--print',
|
|
||||||
'--verbose',
|
|
||||||
'--sdk-url',
|
|
||||||
sdkUrl,
|
sdkUrl,
|
||||||
'--enable-auth-status',
|
shouldResume,
|
||||||
'--input-format',
|
options,
|
||||||
'stream-json',
|
)
|
||||||
'--output-format',
|
|
||||||
'stream-json',
|
|
||||||
...(shouldResume ? ['--resume', sessionId] : ['--session-id', sessionId]),
|
|
||||||
'--replay-user-messages',
|
|
||||||
...this.getRuntimeArgs(options),
|
|
||||||
...this.getPermissionArgs(options?.permissionMode, dangerousMode),
|
|
||||||
])
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`[ConversationService] Starting CLI for ${sessionId}, cwd: ${workDir} (process.cwd()=${process.cwd()}, CALLER_DIR will be pinned to workDir)`,
|
`[ConversationService] Starting CLI for ${sessionId}, cwd: ${workDir} (process.cwd()=${process.cwd()}, CALLER_DIR will be pinned to workDir)`,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user