fix: replace AiGateway.embedBatch with direct LiteLLM cURL for upload indexing
AiGateway uses getenv(LITELLM_MASTER_KEY) + stream_context HTTP which was failing on the chloe virtualhost process. New dbnToolsLiteLLMEmbedBatch() helper mirrors dbnToolsCallGpuLlm — hardcoded URL + key, cURL-first, same pattern already proven for LLM calls. Removes AiGateway dependency from DeepResearchAgent entirely. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,6 @@ final class DbnDeepResearchAgent
|
|||||||
private const POOL_CAP = 30;
|
private const POOL_CAP = 30;
|
||||||
|
|
||||||
private DbnAzureOpenAiGateway $azure;
|
private DbnAzureOpenAiGateway $azure;
|
||||||
private ?AiGateway $ai = null;
|
|
||||||
private array $uploadVecs = [];
|
private array $uploadVecs = [];
|
||||||
private array $stepTimings = [];
|
private array $stepTimings = [];
|
||||||
|
|
||||||
@@ -50,9 +49,7 @@ final class DbnDeepResearchAgent
|
|||||||
dbnToolsBootCaveau();
|
dbnToolsBootCaveau();
|
||||||
$aiPortalRoot = dbnToolsAiPortalRoot();
|
$aiPortalRoot = dbnToolsAiPortalRoot();
|
||||||
require_once $aiPortalRoot . '/platform/includes/dbn_v6.php';
|
require_once $aiPortalRoot . '/platform/includes/dbn_v6.php';
|
||||||
require_once $aiPortalRoot . '/lib/ai/AiGateway.php';
|
|
||||||
|
|
||||||
$this->ai = new AiGateway();
|
|
||||||
$this->uploadVecs = [];
|
$this->uploadVecs = [];
|
||||||
$this->stepTimings = [];
|
$this->stepTimings = [];
|
||||||
|
|
||||||
@@ -141,7 +138,7 @@ final class DbnDeepResearchAgent
|
|||||||
if ($uploadChunks) {
|
if ($uploadChunks) {
|
||||||
try {
|
try {
|
||||||
$texts = array_map(fn(array $c) => $c['text'], $uploadChunks);
|
$texts = array_map(fn(array $c) => $c['text'], $uploadChunks);
|
||||||
$vecs = $this->ai->embedBatch($texts, 'nomic-embed-text');
|
$vecs = dbnToolsLiteLLMEmbedBatch($texts);
|
||||||
if (count($vecs) === count($uploadChunks)) {
|
if (count($vecs) === count($uploadChunks)) {
|
||||||
foreach ($uploadChunks as $i => $chunk) {
|
foreach ($uploadChunks as $i => $chunk) {
|
||||||
$this->uploadVecs[] = [
|
$this->uploadVecs[] = [
|
||||||
@@ -531,7 +528,7 @@ PROMPT;
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$qVec = $this->ai->embed($question, 'nomic-embed-text');
|
$qVec = dbnToolsLiteLLMEmbedBatch([$question])[0] ?? [];
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
error_log('DBN deep research sub-Q embed failed: ' . $e->getMessage());
|
error_log('DBN deep research sub-Q embed failed: ' . $e->getMessage());
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -676,3 +676,72 @@ function dbnToolsCallGpuLlm(array $messages, array $options = []): array
|
|||||||
}
|
}
|
||||||
return $decoded;
|
return $decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch-embed texts via LiteLLM /v1/embeddings using cURL.
|
||||||
|
* Returns an array of float[] indexed by input position.
|
||||||
|
*/
|
||||||
|
function dbnToolsLiteLLMEmbedBatch(array $texts, string $model = 'nomic-embed-text', int $timeout = 60): array
|
||||||
|
{
|
||||||
|
if (empty($texts)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = 'http://10.0.1.10:4000/v1/embeddings';
|
||||||
|
$apiKey = (string)(dbnToolsEnv('LITELLM_MASTER_KEY') ?: 'sk-bnl-litellm-26xR9mK4qvN3wL8sTj7pB2d');
|
||||||
|
|
||||||
|
$payload = json_encode(['model' => $model, 'input' => array_values($texts)], JSON_UNESCAPED_UNICODE);
|
||||||
|
$headers = [
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Authorization: Bearer ' . $apiKey,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (function_exists('curl_init')) {
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $payload,
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
CURLOPT_TIMEOUT => $timeout,
|
||||||
|
]);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||||||
|
$err = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($response === false) {
|
||||||
|
throw new RuntimeException('LiteLLM embed request failed: ' . $err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ctx = stream_context_create(['http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => implode("\r\n", $headers),
|
||||||
|
'content' => $payload,
|
||||||
|
'timeout' => $timeout,
|
||||||
|
'ignore_errors' => true,
|
||||||
|
]]);
|
||||||
|
$response = @file_get_contents($url, false, $ctx);
|
||||||
|
$code = 0;
|
||||||
|
if (isset($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $m)) {
|
||||||
|
$code = (int)$m[1];
|
||||||
|
}
|
||||||
|
if ($response === false) {
|
||||||
|
throw new RuntimeException('LiteLLM embed request failed.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode($response, true);
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
throw new RuntimeException('LiteLLM embed returned non-JSON.');
|
||||||
|
}
|
||||||
|
if ($code < 200 || $code >= 300) {
|
||||||
|
$msg = $decoded['error']['message'] ?? ('HTTP ' . $code);
|
||||||
|
throw new RuntimeException('LiteLLM embed error: ' . $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenAI /v1/embeddings returns data[].embedding ordered by index
|
||||||
|
$data = $decoded['data'] ?? [];
|
||||||
|
usort($data, fn($a, $b) => ($a['index'] ?? 0) <=> ($b['index'] ?? 0));
|
||||||
|
return array_map(fn($d) => $d['embedding'], $data);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user