This commit is contained in:
Your Name
2026-10-27 14:03:35 +08:00
parent 7986e4baf5
commit f9cbd42113
417 changed files with 71876 additions and 5344 deletions
@@ -43,6 +43,10 @@ namespace app\common\service {
function config(string $name): array { return $GLOBALS['largeConfig']; }
function microtime(bool $asFloat = false): float { return $GLOBALS['largeClock']; }
function hrtime(bool $asNumber = false): int|array {
$now = (int) round($GLOBALS['largeClock'] * 1000000000);
return $asNumber ? $now : [intdiv($now, 1000000000), $now % 1000000000];
}
function curl_init(): \stdClass { return (object) ['errno' => 0, 'code' => 200]; }
function curl_setopt_array(\stdClass $handle, array $options): bool { $handle->options = $options; return true; }
function curl_exec(\stdClass $handle): string|bool {
@@ -75,16 +79,35 @@ namespace app\common\service {
}
$duration = $scenario === 'extraction-deadline' && $extract ? 31.0
: ($scenario === 'synthesis-deadline' ? 20.0 : 0.001);
$streaming = ($payload['response_mode'] ?? '') === 'streaming';
$headerSent = false;
if ($streaming && $handle->code === 200) {
($options[CURLOPT_HEADERFUNCTION])($handle, "HTTP/1.1 200 Synthetic\r\n");
$headerSent = true;
($options[CURLOPT_WRITEFUNCTION])($handle, 'data: ' . json_encode([
'event' => 'workflow_started', 'task_id' => 'large-task-' . count($GLOBALS['largeRequests']),
]) . "\n\n");
}
// Model the progress pump's monotonic generation deadline separately
// from libcurl's larger, bounded stop/terminal-drain transport cap.
$progress = $options[defined('CURLOPT_XFERINFOFUNCTION') ? CURLOPT_XFERINFOFUNCTION : CURLOPT_PROGRESSFUNCTION] ?? null;
$advanceMs = min((int) round($duration * 1000), $limitMs);
for ($elapsedMs = 0; $elapsedMs < $advanceMs;) {
$stepMs = min(100, $advanceMs - $elapsedMs);
$GLOBALS['largeClock'] += $stepMs / 1000;
$elapsedMs += $stepMs;
if (is_callable($progress) && $progress($handle, 0, 0, 100, 100)) {
$handle->errno = CURLE_ABORTED_BY_CALLBACK;
return false;
}
}
if ($duration * 1000 >= $limitMs) {
$GLOBALS['largeClock'] += $limitMs / 1000;
$handle->errno = CURLE_OPERATION_TIMEDOUT; $handle->code = 0;
return false;
}
$GLOBALS['largeClock'] += $duration;
if (isset($options[CURLOPT_HEADERFUNCTION])) {
if (!$headerSent && isset($options[CURLOPT_HEADERFUNCTION])) {
($options[CURLOPT_HEADERFUNCTION])($handle, 'HTTP/1.1 ' . $handle->code . " Synthetic\r\n");
}
$streaming = ($payload['response_mode'] ?? '') === 'streaming';
if ($error !== null) {
$body = json_encode($error);
if ($streaming) { ($options[CURLOPT_WRITEFUNCTION])($handle, $body); return true; }
@@ -114,6 +137,7 @@ namespace app\common\service {
}
namespace {
require_once dirname(__DIR__) . '/app/common/service/DifyReasoningTextFilter.php';
require dirname(__DIR__) . '/app/common/service/DifyChatService.php';
use app\common\service\DifyChatService;
@@ -143,6 +167,7 @@ namespace {
$GLOBALS['largeScenario'] = $scenario; $GLOBALS['largeClock'] = 1000.0;
$GLOBALS['largeRequests'] = []; $GLOBALS['largeUploads'] = []; $GLOBALS['largeLogs'] = [];
$GLOBALS['largeExtracts'] = 0; $GLOBALS['largeStops'] = 0; $GLOBALS['largeCancelled'] = false;
$GLOBALS['largeTimeoutClock'] = null;
$GLOBALS['largeMissing'] = [];
$GLOBALS['largeConfig'] = ['enable' => true, 'base_url' => 'https://synthetic.invalid/v1/chat-messages',
'timeout' => 90, 'required_attachment_transport' => 'upload', 'max_files' => 3,
@@ -154,6 +179,7 @@ namespace {
['key' => 'basic_info', 'status' => 'prepared', 'availability' => 'present'],
['key' => 'chat', 'status' => 'prepared', 'availability' => 'present'],
], 'on_progress' => static function (array $event) use (&$events): void { $events[] = $event; },
'on_timeout' => static function (): void { $GLOBALS['largeTimeoutClock'] = $GLOBALS['largeClock']; },
'on_task' => static function (...$args) use (&$tasks): void { $tasks[] = $args; },
'on_transfer_end' => static function (...$args) use (&$ends): void { $ends[] = $args; }];
$inputs = ['full_original_inputs' => $query];
@@ -232,10 +258,13 @@ namespace {
['result' => $result, 'deltas' => $deltas, 'events' => $events] = largeRun(largeFiles(40), $streaming);
largeExpect(empty($result['ok']) && $result['error_code'] === 'UPSTREAM_TIMEOUT', 'whole shared 90-second budget also constrains final synthesis');
$expected = $scenario === 'extraction-deadline' ? 3 : 5;
largeExpect(count($largeRequests) === $expected && abs($largeClock - 1090.0) < 0.01,
'later batches do not receive fresh ninety-second budgets');
largeExpect($largeRequests[count($largeRequests) - 1]['limitMs'] <= ($scenario === 'extraction-deadline' ? 28000 : 10000),
'real curl millisecond option receives remaining aggregate budget');
largeExpect(count($largeRequests) === $expected
&& ($streaming ? abs($largeTimeoutClock - 1090.0) < 0.01 && $largeClock <= 1092.51
: abs($largeClock - 1090.0) < 0.01),
'later batches share ninety seconds of generation; only bounded stop/terminal draining may follow');
largeExpect($largeRequests[count($largeRequests) - 1]['limitMs']
<= ($scenario === 'extraction-deadline' ? 28000 : 10000) + ($streaming ? 2500 : 0),
'curl cap is the remaining aggregate generation budget plus streaming cleanup, never a fresh budget');
largeExpect($deltas === [], 'no extracted intermediate evidence is promoted to partial clinical answer on timeout');
largeSafe($result, $events); $cases++;
}