options = $options; $GLOBALS['ancientReuseRequests'][] = json_decode($options[CURLOPT_POSTFIELDS], true); return true; } function curl_exec(\stdClass $handle): string { $options = $handle->options; if (isset($options[CURLOPT_WRITEFUNCTION])) { $options[CURLOPT_HEADERFUNCTION]($handle, "HTTP/1.1 200 OK\r\n"); $options[CURLOPT_WRITEFUNCTION]($handle, "data: {\"event\":\"message\",\"answer\":\"offline\"}\n\n" . "data: {\"event\":\"message_end\"}\n\n"); return ''; } return '{"answer":"offline"}'; } function curl_errno(\stdClass $handle): int { return 0; } function curl_getinfo(\stdClass $handle, int $option): int { return 200; } function curl_close(\stdClass $handle): void {} } namespace { require dirname(__DIR__) . '/vendor/autoload.php'; use app\common\service\ClinicalKnowledgeReference; use app\common\service\DifyChatService; use app\common\service\TcmAncientBooksReference; function ancientReuseExpect(bool $condition, string $message): void { if (!$condition) { fwrite(STDERR, "FAIL: {$message}\n"); exit(1); } } $indexProperty = new ReflectionProperty(TcmAncientBooksReference::class, 'index'); $indexProperty->setValue(null, [ 'commit' => TcmAncientBooksReference::COMMIT, 'index_version' => TcmAncientBooksReference::INDEX_VERSION, 'terms' => [ '消渴' => [[ 'title' => '甲书', 'chapter' => '消渴篇', 'path' => '甲书.txt', 'line' => 42, 'excerpt' => '消渴原文。', 'score' => 15, ]], ], 'chapter_terms' => [ '痛风' => [[ 'title' => '乙书', 'chapter' => '痛风篇', 'path' => '乙书.txt', 'line' => 88, 'excerpt' => '痛风原文。', 'score' => 12, ]], ], ]); $ancientReuseConfig = [ 'enable' => true, 'base_url' => 'https://ai.example.test/v1/chat-messages', 'timeout' => 30, 'models' => ['qwen' => ['name' => 'offline', 'api_key' => 'test-key']], ]; foreach (['患者糖尿病,请分析。', '患者痛风,请分析。', '患者有未收录的症状。'] as $case) { $expectedSources = ClinicalKnowledgeReference::ancientBookSources($case); $expectedPrompt = ClinicalKnowledgeReference::augmentQuery($case); foreach (['blocking', 'streaming'] as $mode) { $ancientReuseRequests = []; if ($mode === 'blocking') { $result = DifyChatService::chat('qwen', [], $case, 'offline-user'); } else { $deltas = []; $result = DifyChatService::streamChat('qwen', [], $case, 'offline-user', static function (string $delta) use (&$deltas): void { $deltas[] = $delta; }); ancientReuseExpect($deltas === ['offline'], 'streaming forwards the upstream delta'); } ancientReuseExpect($result['ok'] === true, "$mode request succeeds"); ancientReuseExpect(count($ancientReuseRequests) === 1, "$mode sends one request"); ancientReuseExpect($ancientReuseRequests[0]['query'] === $expectedPrompt, "$mode prompt remains byte-for-byte identical"); ancientReuseExpect($result['ancient_book_sources'] === $expectedSources, "$mode returns exactly the selected citations"); } } $indexProperty->setValue(null, null); echo "Dify ancient-books reuse contract passed.\n"; }