deep-research.test.js 3.32 KB
/**
 * 46 号文档 Phase 2:deep-research 按需触发 org-hunt 的轻量调研钩子。
 *
 * 最重要的一条是"默认关闭"这条安全阀——`ENABLE_DEEP_RESEARCH` 不为 `'1'` 时,
 * 连注入的假实现都不应该被调用到,直接短路返回 null(避免真事故:Phase 1 就因为
 * 一个新触发点疏于隔离,一次单测跑出 44 个残留 CLI 子进程)。
 */
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import {
  triggerDeepResearch, setTriggerDeepResearch, buildResearchPrompt,
} from '../../services/deep-research.js';

describe('deep-research · triggerDeepResearch', () => {
  const ORIGINAL_ENABLE = process.env.ENABLE_DEEP_RESEARCH;

  beforeEach(() => {
    setTriggerDeepResearch(null);
  });
  afterEach(() => {
    setTriggerDeepResearch(null);
    if (ORIGINAL_ENABLE === undefined) delete process.env.ENABLE_DEEP_RESEARCH;
    else process.env.ENABLE_DEEP_RESEARCH = ORIGINAL_ENABLE;
  });

  it('ENABLE_DEEP_RESEARCH 未开启时直接返回 null,不调用任何实现(哪怕注入了假实现)', async () => {
    delete process.env.ENABLE_DEEP_RESEARCH;
    let called = false;
    setTriggerDeepResearch(async () => { called = true; return { findings: 'x', sources: [], tokens: 1 }; });

    const out = await triggerDeepResearch({ companyId: 'co-x', task: { id: 'T-1' }, topic: '贪吃蛇怎么做' });
    expect(out).toBeNull();
    expect(called).toBe(false);
  });

  it('开启后走注入实现,返回其结果', async () => {
    process.env.ENABLE_DEEP_RESEARCH = '1';
    setTriggerDeepResearch(async (ctx) => {
      expect(ctx.topic).toBe('贪吃蛇怎么做');
      return { findings: '业界通常先定义棋盘再做碰撞检测', sources: ['https://example.com'], tokens: 123 };
    });

    const out = await triggerDeepResearch({ companyId: 'co-x', task: { id: 'T-1' }, topic: '贪吃蛇怎么做' });
    expect(out).toEqual({
      findings: '业界通常先定义棋盘再做碰撞检测',
      sources: ['https://example.com'],
      tokens: 123,
    });
  });

  it('开启后注入实现抛错:吞掉,返回 null,不向调用方传播', async () => {
    process.env.ENABLE_DEEP_RESEARCH = '1';
    setTriggerDeepResearch(async () => { throw new Error('CLI 起不来'); });

    await expect(
      triggerDeepResearch({ companyId: 'co-x', task: { id: 'T-1' }, topic: 't' })
    ).resolves.toBeNull();
  });

  it('VITEST 环境且未注入时即使开启开关也跳过真实调用', async () => {
    process.env.ENABLE_DEEP_RESEARCH = '1';
    // 不调用 setTriggerDeepResearch,保持默认实现——process.env.VITEST 由 vitest 自动置位
    const out = await triggerDeepResearch({ companyId: 'co-x', task: { id: 'T-1' }, topic: 't' });
    expect(out).toBeNull();
  });
});

describe('deep-research · buildResearchPrompt', () => {
  it('提示词包含调研主题、交回格式,明确说明不套用训练场景三件套契约', () => {
    const prompt = buildResearchPrompt({ topic: '贪吃蛇怎么做' });
    expect(prompt).toContain('贪吃蛇怎么做');
    expect(prompt).toContain('findings');
    expect(prompt).toContain('sources');
    expect(prompt).toContain('不需要');
  });

  it('主题缺失时给出明确占位', () => {
    const prompt = buildResearchPrompt({});
    expect(prompt).toContain('调用方没给主题');
  });
});