更新
This commit is contained in:
@@ -59,6 +59,14 @@ $logic = file_get_contents(dirname(__DIR__) . '/app/adminapi/logic/tcm/Diagnosis
|
||||
$validate = file_get_contents(dirname(__DIR__) . '/app/adminapi/validate/tcm/DiagnosisValidate.php');
|
||||
$auth = file_get_contents(dirname(__DIR__) . '/app/adminapi/http/middleware/AuthMiddleware.php');
|
||||
assistantStreamExpect(is_string($controller) && is_string($logic) && is_string($validate) && is_string($auth), 'stream implementation sources are readable');
|
||||
assistantStreamExpect(
|
||||
str_contains($controller, 'diagnosis ai assistant sse failed'),
|
||||
'unexpected SSE failures retain a privacy-safe server log entry'
|
||||
);
|
||||
assistantStreamExpect(
|
||||
!str_contains($controller, "'exception_message' => \$e->getMessage()"),
|
||||
'unexpected SSE failures never log raw exception messages'
|
||||
);
|
||||
|
||||
$actionStart = strpos($controller, 'public function aiAssistantStream()');
|
||||
$checkAt = strpos($controller, "goCheck('aiAssistant')", $actionStart);
|
||||
|
||||
@@ -115,8 +115,15 @@ difyStreamExpect(
|
||||
callDifyStreamPrivate('shouldTryNextProtocol', [[
|
||||
'errno' => 0,
|
||||
'http_code' => 400,
|
||||
], false]) === false,
|
||||
'business input rejection is not hidden by an alternate protocol attempt'
|
||||
);
|
||||
difyStreamExpect(
|
||||
callDifyStreamPrivate('shouldTryNextProtocol', [[
|
||||
'errno' => 0,
|
||||
'http_code' => 404,
|
||||
], false]) === true,
|
||||
'an ambiguous endpoint rejected before generation tries the alternate protocol'
|
||||
'an unavailable path tries the alternate protocol'
|
||||
);
|
||||
difyStreamExpect(
|
||||
callDifyStreamPrivate('shouldTryNextProtocol', [[
|
||||
|
||||
@@ -186,6 +186,80 @@ expectSame([], $plan[1]['files'], 'the fallback attempt sends no attachments');
|
||||
expectSame(9, count($plan[1]['omitted']), 'the fallback attempt declares every attachment');
|
||||
expectSame(1, count(callPrivate('buildAttemptPlan', [[], []])), 'a request without attachments is attempted once');
|
||||
|
||||
$inputPlan = callPrivate('buildInputAttemptPlan', [['prompt_version' => 'v2']]);
|
||||
expectSame(2, count($inputPlan), 'structured Dify inputs get one compatibility fallback');
|
||||
expectSame([], $inputPlan[1], 'the compatibility fallback uses an empty inputs object');
|
||||
expectSame([[]], callPrivate('buildInputAttemptPlan', [[]]), 'empty inputs are not retried twice');
|
||||
|
||||
$difyInputSpec = ['protocol' => 'dify'];
|
||||
$openAiInputSpec = ['protocol' => 'openai'];
|
||||
expectSame(
|
||||
true,
|
||||
callPrivate('isInputRejection', [
|
||||
['errno' => 0, 'http_code' => 400, 'body' => '{"code":"invalid_param"}'],
|
||||
$difyInputSpec,
|
||||
['prompt_version' => 'v2'],
|
||||
]),
|
||||
'Dify invalid_param retries with query-only input'
|
||||
);
|
||||
expectSame(
|
||||
false,
|
||||
callPrivate('isInputRejection', [
|
||||
['errno' => 0, 'http_code' => 400, 'body' => '{"code":"invalid_param"}'],
|
||||
$difyInputSpec,
|
||||
[],
|
||||
]),
|
||||
'an already empty inputs object is never retried'
|
||||
);
|
||||
expectSame(
|
||||
false,
|
||||
callPrivate('isInputRejection', [
|
||||
['errno' => 0, 'http_code' => 400, 'body' => '{"code":"invalid_param"}'],
|
||||
$openAiInputSpec,
|
||||
['prompt_version' => 'v2'],
|
||||
]),
|
||||
'OpenAI protocol does not use the Dify input fallback'
|
||||
);
|
||||
expectSame(
|
||||
false,
|
||||
callPrivate('isInputRejection', [
|
||||
['errno' => 0, 'http_code' => 400, 'body' => '{"code":"provider_quota_exceeded"}'],
|
||||
$difyInputSpec,
|
||||
['prompt_version' => 'v2'],
|
||||
]),
|
||||
'quota and provider failures are not submitted twice'
|
||||
);
|
||||
expectSame(
|
||||
true,
|
||||
callPrivate('isInputRejection', [
|
||||
[
|
||||
'errno' => 0,
|
||||
'http_code' => 200,
|
||||
'upstream_error' => true,
|
||||
'upstream_code' => 'invalid_param',
|
||||
'emitted' => false,
|
||||
],
|
||||
$difyInputSpec,
|
||||
['prompt_version' => 'v2'],
|
||||
]),
|
||||
'a streaming invalid_param before any delta also retries without inputs'
|
||||
);
|
||||
expectSame(
|
||||
false,
|
||||
callPrivate('isInputRejection', [
|
||||
[
|
||||
'errno' => 0,
|
||||
'http_code' => 200,
|
||||
'upstream_error' => true,
|
||||
'upstream_code' => 'invalid_param',
|
||||
'emitted' => true,
|
||||
],
|
||||
$difyInputSpec,
|
||||
['prompt_version' => 'v2'],
|
||||
]),
|
||||
'a stream that already emitted content is never replayed'
|
||||
);
|
||||
|
||||
expectSame(true, callPrivate('shouldRetryWithoutFiles', [400, $capped['kept']]), 'invalid_param retries without attachments');
|
||||
expectSame(true, callPrivate('shouldRetryWithoutFiles', [413, $capped['kept']]), 'oversized attachments retry without attachments');
|
||||
expectSame(false, callPrivate('shouldRetryWithoutFiles', [400, []]), 'a text-only rejection is not retried');
|
||||
|
||||
Reference in New Issue
Block a user