Fix cronjob/telegram fallback for keyless server-key providers
Cronjobs and Telegram bots threw a hard error when an agent had no assigned user API key, even for providers (nvidia/gemini/minimax/ pollinations) whose server-side key ChatEndpoint resolves automatically via ResolveProviderConfig. The guard blocked every non-empty provider instead of only "openai", so e.g. the nvidia agent failed on "Jetzt ausführen" although the normal chat worked. Mirror ChatEndpoint's three-way handling at all three sites (ExecuteCronjob, SendCronjobNotification, TelegramService.HandleMessage): - Anthropic (empty provider): Claude CLI fallback when permitted/available - "openai": hard error (no server key, no CLI equivalent) - other providers: pass through with empty token; server key resolved later Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
f99c3c1db9
commit
e3f89043c1
2 files changed
+85
-24
No files matched your search
@@ -91,9 +91,37 @@ public class CronjobService : BackgroundService
|
||||
|
||||
// API-Key des Cronjob-Owners für diesen Agent auflösen
|
||||
var userApiKey = await _db.GetAgentApiKeyRecord(job.UserId, ctx.AgentId);
|
||||
bool useCliFallback = false;
|
||||
|
||||
if (userApiKey == null)
|
||||
throw new Exception($"Kein API-Key für Agent {ctx.AgentId} zugewiesen (User {job.UserId})");
|
||||
ctx.ApiToken = userApiKey.ApiKey;
|
||||
{
|
||||
// Kein User-Key – Verhalten exakt wie ChatEndpoint:
|
||||
// - Anthropic (Provider leer) → Claude-CLI-Fallback (sofern berechtigt/verfügbar)
|
||||
// - "openai" → harter Fehler (kein Server-Key, kein CLI-Äquivalent)
|
||||
// - nvidia/gemini/minimax/pollinations → durchlassen: ResolveProviderConfig löst den Server-Key auf
|
||||
if (string.IsNullOrEmpty(ctx.Provider))
|
||||
{
|
||||
var jobOwner = await _db.GetUser(job.UserId);
|
||||
if (jobOwner != null && !jobOwner.CanUseCli && !jobOwner.IsAdmin)
|
||||
throw new Exception($"Kein API-Key für Agent {ctx.AgentId} zugewiesen und User {job.UserId} hat keine CLI-Berechtigung.");
|
||||
|
||||
if (!_anthropicService.IsCliAvailable)
|
||||
throw new Exception($"Kein API-Key für Agent {ctx.AgentId} zugewiesen und Claude CLI nicht verfügbar.");
|
||||
|
||||
useCliFallback = true;
|
||||
_logger.LogInformation("Cronjob '{Name}': Kein API-Key für Agent {AgentId}, verwende CLI-Fallback", job.Name, ctx.AgentId);
|
||||
}
|
||||
else if (ctx.Provider == "openai")
|
||||
{
|
||||
throw new Exception($"Kein API-Key für Agent {ctx.AgentId} zugewiesen (User {job.UserId}). OpenAI benötigt zwingend einen zugewiesenen API-Key.");
|
||||
}
|
||||
// sonst: nvidia/gemini/minimax/pollinations → ctx.ApiToken bleibt leer,
|
||||
// der Server-seitige Provider-Key wird in ResolveProviderConfig aufgelöst.
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.ApiToken = userApiKey.ApiKey;
|
||||
}
|
||||
|
||||
// History aus DB laden. includeThinking=true für OpenAI-kompatible Provider →
|
||||
// <think>...</think>-Prefix wird dem Assistant-Text vorangestellt.
|
||||
@@ -117,6 +145,8 @@ public class CronjobService : BackgroundService
|
||||
string responseText;
|
||||
if (!string.IsNullOrEmpty(ctx.Provider))
|
||||
responseText = await _openAiService.ChatNonStreaming(ctx, history);
|
||||
else if (useCliFallback)
|
||||
responseText = await _anthropicService.ChatNonStreamingViaCli(ctx, history);
|
||||
else
|
||||
responseText = await _anthropicService.ChatNonStreaming(ctx, history);
|
||||
|
||||
@@ -150,12 +180,36 @@ public class CronjobService : BackgroundService
|
||||
|
||||
// API-Key des Cronjob-Owners für Notify-Agent auflösen
|
||||
var notifyApiKey = await _db.GetAgentApiKeyRecord(job.UserId, notifyCtx.AgentId);
|
||||
bool notifyUseCliFallback = false;
|
||||
|
||||
if (notifyApiKey == null)
|
||||
{
|
||||
_logger.LogWarning("Kein API-Key für Agent {AgentId} (Cronjob '{Name}' Notification)", notifyCtx.AgentId, job.Name);
|
||||
return;
|
||||
// Kein User-Key – Verhalten wie ExecuteCronjob/ChatEndpoint:
|
||||
// - Anthropic (Provider leer) → Claude-CLI-Fallback (sofern berechtigt/verfügbar)
|
||||
// - "openai" → abbrechen (kein Server-Key, kein CLI-Äquivalent)
|
||||
// - nvidia/gemini/minimax/pollinations → durchlassen: Server-Key via ResolveProviderConfig
|
||||
if (string.IsNullOrEmpty(notifyCtx.Provider))
|
||||
{
|
||||
var notifyOwner = await _db.GetUser(job.UserId);
|
||||
if ((notifyOwner != null && !notifyOwner.CanUseCli && !notifyOwner.IsAdmin) || !_anthropicService.IsCliAvailable)
|
||||
{
|
||||
_logger.LogWarning("Kein API-Key für Agent {AgentId} (Cronjob '{Name}' Notification) und CLI nicht verfügbar/berechtigt", notifyCtx.AgentId, job.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
notifyUseCliFallback = true;
|
||||
}
|
||||
else if (notifyCtx.Provider == "openai")
|
||||
{
|
||||
_logger.LogWarning("Kein API-Key für Agent {AgentId} (Cronjob '{Name}' Notification, OpenAI benötigt zwingend einen Key)", notifyCtx.AgentId, job.Name);
|
||||
return;
|
||||
}
|
||||
// sonst: nvidia/gemini/minimax/pollinations → notifyCtx.ApiToken bleibt leer (Server-Key-Auflösung).
|
||||
}
|
||||
else
|
||||
{
|
||||
notifyCtx.ApiToken = notifyApiKey.ApiKey;
|
||||
}
|
||||
notifyCtx.ApiToken = notifyApiKey.ApiKey;
|
||||
|
||||
// Kurze Zusammenfassung als User-Nachricht in die Notify-Session schreiben
|
||||
var summary = $"[Cronjob \"{job.Name}\" wurde in Session \"{job.SessionName}\" ausgeführt]\n\nAntwort:\n{Truncate(responseText, 2000)}";
|
||||
@@ -183,6 +237,8 @@ public class CronjobService : BackgroundService
|
||||
string notifyResponse;
|
||||
if (!string.IsNullOrEmpty(notifyCtx.Provider))
|
||||
notifyResponse = await _openAiService.ChatNonStreaming(notifyCtx, notifyHistory);
|
||||
else if (notifyUseCliFallback)
|
||||
notifyResponse = await _anthropicService.ChatNonStreamingViaCli(notifyCtx, notifyHistory);
|
||||
else
|
||||
notifyResponse = await _anthropicService.ChatNonStreaming(notifyCtx, notifyHistory);
|
||||
|
||||
|
||||
Reference in new issue
Block a user