|
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | */ |
6 | 6 |
|
7 | | -import { describe, it, expect, vi, beforeEach } from 'vitest'; |
| 7 | +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; |
| 8 | +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; |
| 9 | +import { tmpdir } from 'node:os'; |
| 10 | +import { join } from 'node:path'; |
8 | 11 | import type { Config } from '@qwen-code/qwen-code-core'; |
9 | 12 | import type { TurnContent, MessageRewriteConfig } from './types.js'; |
10 | 13 |
|
@@ -278,4 +281,65 @@ describe('LlmRewriter', () => { |
278 | 281 | expect(input).not.toContain('上一轮改写结果'); |
279 | 282 | }); |
280 | 283 | }); |
| 284 | + |
| 285 | + describe('promptFile', () => { |
| 286 | + let tempDir: string; |
| 287 | + |
| 288 | + beforeEach(() => { |
| 289 | + tempDir = mkdtempSync(join(tmpdir(), 'llm-rewriter-promptfile-')); |
| 290 | + }); |
| 291 | + |
| 292 | + afterEach(() => { |
| 293 | + rmSync(tempDir, { recursive: true, force: true }); |
| 294 | + }); |
| 295 | + |
| 296 | + function promptOf(rewriter: unknown): string { |
| 297 | + return (rewriter as { prompt: string }).prompt; |
| 298 | + } |
| 299 | + |
| 300 | + it('loads a custom prompt from a readable file', () => { |
| 301 | + const filePath = join(tempDir, 'prompt.md'); |
| 302 | + writeFileSync(filePath, ' custom rewrite prompt '); |
| 303 | + |
| 304 | + const rewriter = new LlmRewriter(makeConfig(), { |
| 305 | + enabled: true, |
| 306 | + target: 'all', |
| 307 | + promptFile: filePath, |
| 308 | + } as MessageRewriteConfig); |
| 309 | + |
| 310 | + expect(promptOf(rewriter)).toBe('custom rewrite prompt'); |
| 311 | + }); |
| 312 | + |
| 313 | + it('falls back to the default prompt when the file is missing', () => { |
| 314 | + const rewriter = new LlmRewriter(makeConfig(), { |
| 315 | + enabled: true, |
| 316 | + target: 'all', |
| 317 | + promptFile: join(tempDir, 'does-not-exist.md'), |
| 318 | + } as MessageRewriteConfig); |
| 319 | + |
| 320 | + expect(promptOf(rewriter)).toContain('rewrites raw coding-agent output'); |
| 321 | + }); |
| 322 | + |
| 323 | + // Regression for #9752: promptFile pointing at a path that exists but |
| 324 | + // cannot be read as a file (a directory) used to throw EISDIR from the |
| 325 | + // constructor, crashing ACP session startup. |
| 326 | + it('falls back to the default prompt when promptFile is a directory', () => { |
| 327 | + expect( |
| 328 | + () => |
| 329 | + new LlmRewriter(makeConfig(), { |
| 330 | + enabled: true, |
| 331 | + target: 'all', |
| 332 | + promptFile: tempDir, |
| 333 | + } as MessageRewriteConfig), |
| 334 | + ).not.toThrow(); |
| 335 | + |
| 336 | + const rewriter = new LlmRewriter(makeConfig(), { |
| 337 | + enabled: true, |
| 338 | + target: 'all', |
| 339 | + promptFile: tempDir, |
| 340 | + } as MessageRewriteConfig); |
| 341 | + |
| 342 | + expect(promptOf(rewriter)).toContain('rewrites raw coding-agent output'); |
| 343 | + }); |
| 344 | + }); |
281 | 345 | }); |
0 commit comments