mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
fix(wiki): address local CLI provider review findings
- Add subprocess timeout: LocalCLIConfig gains requestTimeoutMs, runLocalCLI sets a kill timer that rejects with an actionable error matching the HTTP timeout message format. --timeout is no longer silently ignored for claude/codex providers. - Add windowsHide: true to spawn() to prevent console window flash on Windows, matching cursor-client.ts behavior. - Skip GITNEXUS_MODEL env var for local providers so a user's OpenAI model name doesn't cross-contaminate claude/codex CLI invocations. Precedence for local providers: --model → savedLocalModel → ''. - Guard against empty stdout: reject with actionable error when CLI exits 0 but produces no output, preventing silent empty wiki pages.
This commit is contained in:
parent
0f9bf35a1d
commit
0245e60f30
3 changed files with 30 additions and 2 deletions
|
|
@ -222,6 +222,7 @@ export class WikiGenerator {
|
|||
const localConfig = resolveLocalCLIConfig({
|
||||
model: this.llmConfig.model,
|
||||
workingDirectory: this.repoPath,
|
||||
requestTimeoutMs: this.llmConfig.requestTimeoutMs,
|
||||
});
|
||||
return this.llmConfig.provider === 'claude'
|
||||
? callClaudeLLM(prompt, localConfig, systemPrompt, options)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export async function resolveLLMConfig(overrides?: Partial<LLMConfig>): Promise<
|
|||
'https://openrouter.ai/api/v1',
|
||||
model:
|
||||
overrides?.model ||
|
||||
process.env.GITNEXUS_MODEL ||
|
||||
(localProvider ? undefined : process.env.GITNEXUS_MODEL) ||
|
||||
savedLocalModel ||
|
||||
(localProvider ? '' : savedConfig.model || 'minimax/minimax-m2.5'),
|
||||
maxTokens: overrides?.maxTokens ?? 16_384,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export type LocalAgentProvider = 'claude' | 'codex';
|
|||
export interface LocalCLIConfig {
|
||||
model?: string;
|
||||
workingDirectory?: string;
|
||||
requestTimeoutMs?: number;
|
||||
}
|
||||
|
||||
const COMMANDS: Record<LocalAgentProvider, string> = {
|
||||
|
|
@ -62,6 +63,7 @@ export function resolveLocalCLIConfig(overrides?: Partial<LocalCLIConfig>): Loca
|
|||
return {
|
||||
model: overrides?.model,
|
||||
workingDirectory: overrides?.workingDirectory,
|
||||
requestTimeoutMs: overrides?.requestTimeoutMs,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +158,7 @@ function runLocalCLI(
|
|||
const child = spawn(commandInfo.command, finalArgs, {
|
||||
cwd: config.workingDirectory || process.cwd(),
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
windowsHide: true,
|
||||
env: {
|
||||
...process.env,
|
||||
CI: '1',
|
||||
|
|
@ -168,19 +171,38 @@ function runLocalCLI(
|
|||
let stderr = '';
|
||||
let stdinError: Error | undefined;
|
||||
let settled = false;
|
||||
let killTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
const rejectOnce = (error: Error) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
if (killTimer !== undefined) clearTimeout(killTimer);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
const resolveOnce = (response: LLMResponse) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
if (killTimer !== undefined) clearTimeout(killTimer);
|
||||
resolve(response);
|
||||
};
|
||||
|
||||
if (config.requestTimeoutMs !== undefined && config.requestTimeoutMs > 0) {
|
||||
killTimer = setTimeout(() => {
|
||||
child.kill();
|
||||
const duration =
|
||||
config.requestTimeoutMs! >= 60_000
|
||||
? `${Math.round(config.requestTimeoutMs! / 60_000)}m`
|
||||
: `${Math.round(config.requestTimeoutMs! / 1_000)}s`;
|
||||
rejectOnce(
|
||||
new Error(
|
||||
`${provider} CLI timed out after ${duration}. ` +
|
||||
'Increase --timeout or omit it to disable the request timeout.',
|
||||
),
|
||||
);
|
||||
}, config.requestTimeoutMs);
|
||||
}
|
||||
|
||||
child.stdout.on('data', (chunk: Buffer) => {
|
||||
const chunkStr = chunk.toString();
|
||||
stdout += chunkStr;
|
||||
|
|
@ -212,7 +234,12 @@ function runLocalCLI(
|
|||
rejectOnce(new Error(`${provider} CLI stdin error: ${stdinError.message}`));
|
||||
return;
|
||||
}
|
||||
resolveOnce({ content: stdout.trim() });
|
||||
const output = stdout.trim();
|
||||
if (!output) {
|
||||
rejectOnce(new Error(`${provider} CLI returned empty output`));
|
||||
return;
|
||||
}
|
||||
resolveOnce({ content: output });
|
||||
});
|
||||
|
||||
child.on('error', (err) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue