options = $options; $GLOBALS['r37TransportRequests'][] = json_decode($options[CURLOPT_POSTFIELDS], true, 512, JSON_THROW_ON_ERROR); $GLOBALS['r37TransportHeaders'][] = $options[CURLOPT_HTTPHEADER]; return true; } function curl_exec(\stdClass $handle): string { $answer = $GLOBALS['r37TransportAnswer']; if (isset($handle->options[CURLOPT_WRITEFUNCTION])) { $handle->options[CURLOPT_HEADERFUNCTION]($handle, "HTTP/1.1 200 OK\r\n"); $handle->options[CURLOPT_WRITEFUNCTION]($handle, 'data: ' . json_encode(['event' => 'message', 'answer' => $answer], JSON_UNESCAPED_UNICODE) . "\n\n" . "data: {\"event\":\"message_end\"}\n\n"); return ''; } return json_encode(['answer' => $answer], JSON_UNESCAPED_UNICODE); } 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\TcmClinicalResponsePolicy; $checks = 0; function r37TransportExpect(bool $ok, string $message): void { ++$GLOBALS['checks']; if (!$ok) throw new \RuntimeException($message); } $r37TransportConfig = ['enable' => true, 'base_url' => 'https://no-network.invalid/v1/chat-messages', 'timeout' => 30, 'models' => [ 'qwen' => ['name' => 'synthetic-qwen-original', 'api_key' => 'synthetic-qwen'], 'openai' => ['name' => 'synthetic-openai-original', 'api_key' => 'synthetic-openai'], ]]; $tasks = ['case_analysis' => '分析病历', 'glucose_trend' => '血糖趋势', 'medication_review' => '用药评估', 'complication_risk' => '并发症风险', 'summary' => '生成问诊小结', 'lifestyle_advice' => '健康建议']; $raw = '2026-10-10空腹血糖8.2mmol/L;2026-10-12空腹血糖7.6mmol/L。舌象未记录。当前用药未记录。SOURCE_TAIL'; $policy = TcmClinicalResponsePolicy::consultationReference(); r37TransportExpect(str_contains($policy, '完成本次选定任务') && str_contains($policy, '缺项只限定依赖该项的判断'), 'missing data qualify dependent conclusions without disabling other analysis'); r37TransportExpect(str_contains($policy, '不将整个回答改成资料核对') && str_contains($policy, '未记录、未采集与不详保持未知'), 'task answers are analysis and retain unknown states'); r37TransportExpect(str_contains($policy, '脉象不参与本次辨证') && str_contains($policy, '不擅停换'), 'pulse exclusion and medication boundaries remain'); r37TransportExpect(str_contains(TcmClinicalResponsePolicy::reference(), '舌象、脉象各单列'), 'nonconsultation reference behavior stays separate'); foreach ($tasks as $task => $label) foreach (['qwen', 'openai'] as $profile) foreach (['blocking', 'streaming'] as $mode) { $r37TransportRequests = []; $r37TransportHeaders = []; $deltas = []; $r37TransportAnswer = "MODEL::{$task}::{$profile}::{$mode} 已分析现有资料;舌象未记录,相关判断保留不确定性。"; $query = "任务:{$label}\n请根据已有资料分析本任务,缺项明示。\n{$raw}"; $expectedQuery = ClinicalKnowledgeReference::augmentCaseQuery($query, true); $inputs = ['task_marker' => $task, 'case_raw' => $raw]; $options = ['knowledge_mode' => 'clinical', 'reference_scope' => 'consultation']; if ($mode === 'blocking') { $result = DifyChatService::chat($profile, $inputs, $query, 'synthetic-r37-user', [], $options); } else { $result = DifyChatService::streamChat($profile, $inputs, $query, 'synthetic-r37-user', static function (string $delta) use (&$deltas): void { $deltas[] = $delta; }, null, [], $options); r37TransportExpect(implode('', $deltas) === $r37TransportAnswer, "{$task}/{$profile} streaming retains actual model text"); } r37TransportExpect($result['ok'] === true && count($r37TransportRequests) === 1, "{$task}/{$profile}/{$mode} invokes transport exactly once"); r37TransportExpect($result['content'] === $r37TransportAnswer, "{$task}/{$profile}/{$mode} retains model answer without a source-only replacement"); r37TransportExpect($r37TransportRequests[0]['query'] === $expectedQuery && str_ends_with($expectedQuery, $query) && $r37TransportRequests[0]['inputs'] === $inputs, "{$task}/{$profile}/{$mode} preserves task question and all raw inputs"); r37TransportExpect(in_array('Authorization: Bearer synthetic-' . $profile, $r37TransportHeaders[0], true), "{$task}/{$profile}/{$mode} preserves configured provider selection"); r37TransportExpect(ClinicalKnowledgeReference::augmentCaseQuery($expectedQuery, true) === $expectedQuery, 'case query augmentation remains idempotent'); } echo json_encode(['passed' => $checks, 'transport_calls' => 24, 'network_calls' => 0, 'scope' => 'real Dify transport construction with in-process cURL fakes; no real model, clinical acceptance or deployment'], JSON_UNESCAPED_UNICODE) . "\n"; }