feat: configure audio providers and add local sample acceptance
This commit is contained in:
@@ -6,7 +6,7 @@ namespace app\common\service\followupaudio {
|
||||
/** Command-state test double. Actual HTTP/audio behavior is covered by FollowupAudioDifyTest. */
|
||||
final class FollowupAudioDify {
|
||||
public static string $mode = 'uncertain';
|
||||
public static string $fingerprint = 'synthetic-application-one';
|
||||
public static string $fingerprint = '1111111111111111111111111111111111111111111111111111111111111111';
|
||||
public static int $calls = 0;
|
||||
public function configurationStatus(string $profile): array { return ['configured' => true, 'profile' => $profile, 'code' => 'OK', 'application_fingerprint' => self::$fingerprint]; }
|
||||
public function probe(string $path, array $fixture, string $profile, callable $heartbeat): array {
|
||||
@@ -24,6 +24,8 @@ namespace {
|
||||
use app\command\FollowupAudioProbe as Probe;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
new think\App(); // No initialization, real config or DB.
|
||||
$safeConfig = new think\Config(); think\Container::getInstance()->instance('config', $safeConfig);
|
||||
$directory = sys_get_temp_dir() . '/followup-audio-probe-state-' . bin2hex(random_bytes(6));
|
||||
mkdir($directory, 0700, true);
|
||||
$directory = realpath($directory);
|
||||
@@ -52,26 +54,42 @@ namespace {
|
||||
$expect($code === 1 && Dify::$calls === 0 && str_contains($stdout, 'SYNTHETIC_ACK_REQUIRED'), 'explicit synthetic acknowledgement required');
|
||||
[$code, $stdout] = $run('qwen');
|
||||
$expect($code === 2 && Dify::$calls === 1 && str_contains($stdout, 'needs_reconciliation'), 'unknown result stops next cases');
|
||||
$report = json_decode(file_get_contents($directory . '/probe-qwen.json'), true);
|
||||
$report = json_decode(file_get_contents($directory . '/probe-qwen-' . Dify::$fingerprint . '.json'), true);
|
||||
$expect($report['cases']['short']['upstream_started_at'] > 0, 'intent persisted before request');
|
||||
[$code, $stdout] = $run('qwen');
|
||||
$expect($code === 2 && Dify::$calls === 1 && str_contains($stdout, 'NO_RESUBMISSION'), 'resume never recharges unknown result');
|
||||
$currentQwenPath = $directory . '/probe-qwen-' . Dify::$fingerprint . '.json';
|
||||
$legacyQwenPath = $directory . '/probe-qwen.json';
|
||||
rename($currentQwenPath, $legacyQwenPath);
|
||||
$legacyBytes = file_get_contents($legacyQwenPath);
|
||||
[$code, $stdout] = $run('qwen');
|
||||
$expect($code === 2 && Dify::$calls === 1 && str_contains($stdout, 'NO_RESUBMISSION'), 'matching legacy identity remains authoritative for unknown requests');
|
||||
$expect(file_get_contents($legacyQwenPath) === $legacyBytes, 'legacy unknown evidence retained unchanged');
|
||||
$legacyReport = json_decode($legacyBytes, true);
|
||||
$legacyReport['configuration']['application_fingerprint'] = hash('sha256', "https://synthetic.invalid/v1\0synthetic-key");
|
||||
file_put_contents($legacyQwenPath, json_encode($legacyReport));
|
||||
$safeConfig->set(['providers' => ['qwen' => ['driver' => 'dify', 'base_url' => 'https://synthetic.invalid/v1', 'api_key' => 'synthetic-key']]], 'followup_audio');
|
||||
[$code, $stdout] = $run('qwen');
|
||||
$expect($code === 2 && Dify::$calls === 1 && str_contains($stdout, 'NO_RESUBMISSION'), 'legacy Dify hash upgrade cannot resubmit same-app unknown');
|
||||
$safeConfig->set([], 'followup_audio');
|
||||
|
||||
Dify::$mode = 'success';
|
||||
[$code, $stdout] = $run('openai');
|
||||
$expect($code === 0 && Dify::$calls === 4, 'three lengths passed sequentially');
|
||||
$bytes = file_get_contents($directory . '/probe-openai.json');
|
||||
$bytes = file_get_contents($directory . '/probe-openai-' . Dify::$fingerprint . '.json');
|
||||
$report = json_decode($bytes, true);
|
||||
$expect($report['audio_verified'] && count($report['cases']) === 3, 'all three required before verification report');
|
||||
$expect(!str_contains($bytes . $stdout, 'PRIVATE_TRANSCRIPT_NEVER_PRINTED'), 'no transcript in output or report');
|
||||
[$code, $stdout] = $run('openai');
|
||||
$expect($code === 0 && Dify::$calls === 4 && substr_count($stdout, 'retained_passed') === 3, 'passed gate results reused without resending');
|
||||
Dify::$fingerprint = 'synthetic-application-two';
|
||||
$oldPath = $directory . '/probe-openai-' . Dify::$fingerprint . '.json';
|
||||
Dify::$fingerprint = '2222222222222222222222222222222222222222222222222222222222222222';
|
||||
[$code, $stdout] = $run('openai');
|
||||
$expect($code === 1 && Dify::$calls === 4 && str_contains($stdout, 'PROBE_APPLICATION_CHANGED'), 'new application cannot inherit old gate');
|
||||
$expect(file_get_contents($directory . '/probe-openai.json') === $bytes, 'application mismatch leaves original evidence unchanged');
|
||||
$expect($code === 0 && Dify::$calls === 7 && !str_contains($stdout, 'retained_passed'), 'new application executes its own gate');
|
||||
$expect(file_get_contents($oldPath) === $bytes, 'application mismatch leaves original evidence unchanged');
|
||||
file_put_contents($directory . '/short.mp3', 'tampered');
|
||||
[$code, $stdout] = $run('qwen');
|
||||
$expect($code === 1 && Dify::$calls === 4 && str_contains($stdout, 'SYNTHETIC_FIXTURE_REQUIRED'), 'tampered fixture cannot run');
|
||||
$expect($code === 1 && Dify::$calls === 7 && str_contains($stdout, 'SYNTHETIC_FIXTURE_REQUIRED'), 'tampered fixture cannot run');
|
||||
echo 'FOLLOWUP_AUDIO_PROBE_COMMAND assertions=' . $checks . ' PASS durable_no_resend=1 retained_results=1 app_identity=1' . PHP_EOL;
|
||||
} finally {
|
||||
foreach (glob($directory . '/*') ?: [] as $file) { if (is_file($file)) { unlink($file); } }
|
||||
|
||||
Reference in New Issue
Block a user