Add fallback target logging and unified failures
This commit is contained in:
@@ -3,6 +3,7 @@ import {AI_VOICE_MODE_TRANSCRIPT, DEFAULT_AI_RESPONSE_LANGUAGE} from "../common/
|
||||
import {Environment} from "../common/environment";
|
||||
import {UserRequestPipeline, type UserRequestPipelineState, type UserRequestPipelineStage} from "./user-request-pipeline";
|
||||
import {PipelineFallbackNotifier} from "./user-request-pipeline/fallback-notifier";
|
||||
import {buildToolRankFallbackTargetDetails} from "./user-request-pipeline/fallback-target-details";
|
||||
import type {AiDownloadedFile} from "./telegram-attachments";
|
||||
import type {TelegramStreamMessage} from "./telegram-stream-message";
|
||||
import type {ChatMessage} from "./chat-messages-types";
|
||||
@@ -304,6 +305,23 @@ export async function prepareUnifiedAiRequestPipeline(params: {
|
||||
"audit_finish",
|
||||
],
|
||||
onFallback: async decision => {
|
||||
if (decision.action === "use_alternate_target") {
|
||||
aiLog("warn", "request.fallback.use_alternate_target", {
|
||||
provider: options.provider,
|
||||
stage: decision.stage,
|
||||
reason: decision.reason,
|
||||
...buildToolRankFallbackTargetDetails(options.provider, config),
|
||||
});
|
||||
}
|
||||
|
||||
if (decision.action === "fail_request") {
|
||||
aiLog("error", "request.fallback.fail_request", {
|
||||
provider: options.provider,
|
||||
stage: decision.stage,
|
||||
reason: decision.reason,
|
||||
});
|
||||
}
|
||||
|
||||
const notification = await fallbackNotifier.notify(state.requestId, decision);
|
||||
state.audit.push({
|
||||
stage: decision.stage,
|
||||
@@ -315,6 +333,9 @@ export async function prepareUnifiedAiRequestPipeline(params: {
|
||||
fallbackNotification: notification.text,
|
||||
fallbackNotified: notification.notified,
|
||||
reason: decision.reason,
|
||||
...(decision.action === "use_alternate_target"
|
||||
? buildToolRankFallbackTargetDetails(options.provider, config)
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -25,6 +25,7 @@ import {summarizeModelOutput} from "./response-model-output";
|
||||
import {summarizeToolLoop} from "./tool-loop-summary";
|
||||
import {persistToolLoopSummaryArtifactAttachment} from "./tool-loop-artifact-store";
|
||||
import {PipelineFallbackNotifier} from "./user-request-pipeline/fallback-notifier";
|
||||
import {buildToolRankFallbackTargetDetails} from "./user-request-pipeline/fallback-target-details";
|
||||
import {
|
||||
resolveTextToSpeechProviderForUser,
|
||||
sendSynthesizedSpeech,
|
||||
@@ -395,6 +396,23 @@ export async function runUnifiedAiResponsePipeline(params: {
|
||||
"audit_finish",
|
||||
],
|
||||
onFallback: async decision => {
|
||||
if (decision.action === "use_alternate_target") {
|
||||
aiLog("warn", "response.fallback.use_alternate_target", {
|
||||
provider: options.provider,
|
||||
stage: decision.stage,
|
||||
reason: decision.reason,
|
||||
...buildToolRankFallbackTargetDetails(options.provider, config),
|
||||
});
|
||||
}
|
||||
|
||||
if (decision.action === "fail_request") {
|
||||
aiLog("error", "response.fallback.fail_request", {
|
||||
provider: options.provider,
|
||||
stage: decision.stage,
|
||||
reason: decision.reason,
|
||||
});
|
||||
}
|
||||
|
||||
const notification = await fallbackNotifier.notify(state.requestId, decision);
|
||||
state.audit.push({
|
||||
stage: decision.stage,
|
||||
@@ -406,6 +424,9 @@ export async function runUnifiedAiResponsePipeline(params: {
|
||||
fallbackNotification: notification.text,
|
||||
fallbackNotified: notification.notified,
|
||||
reason: decision.reason,
|
||||
...(decision.action === "use_alternate_target"
|
||||
? buildToolRankFallbackTargetDetails(options.provider, config)
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type {PipelineFallbackDecision} from "./fallback-executor.js";
|
||||
|
||||
export class PipelineRequestFailure extends Error {
|
||||
constructor(public readonly decision: PipelineFallbackDecision, message: string) {
|
||||
super(message);
|
||||
this.name = "PipelineRequestFailure";
|
||||
}
|
||||
}
|
||||
|
||||
export function raisePipelineRequestFailure(decision: PipelineFallbackDecision, stageName: string): never {
|
||||
throw new PipelineRequestFailure(decision, `Pipeline send failed at stage ${stageName} with fallback action ${decision.action}`);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import {AiProvider} from "../../model/ai-provider.js";
|
||||
import type {RuntimeConfigSnapshot} from "../unified-ai-runner.shared.js";
|
||||
import {aiLogProviderTarget} from "../../logging/ai-logger.js";
|
||||
import {buildRankerTarget} from "../tool-ranker-pipeline.js";
|
||||
import {providerChatTarget} from "../unified-ai-runner.shared.js";
|
||||
|
||||
export function buildToolRankFallbackTargetDetails(provider: AiProvider, config: RuntimeConfigSnapshot) {
|
||||
const sourceTarget = buildRankerTarget(config, provider);
|
||||
const alternateTarget = providerChatTarget(provider, config);
|
||||
|
||||
return {
|
||||
sourceTarget: aiLogProviderTarget(sourceTarget),
|
||||
alternateTarget: aiLogProviderTarget(alternateTarget),
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import {DEFAULT_PIPELINE_FALLBACK_POLICIES, USER_REQUEST_PIPELINE_STAGES} from "./blueprint.js";
|
||||
import {decidePipelineFallback, type PipelineFallbackDecision} from "./fallback-executor.js";
|
||||
import {raisePipelineRequestFailure} from "./fallback-failure.js";
|
||||
import type {
|
||||
PipelineAuditEvent,
|
||||
PipelineFallbackPolicy,
|
||||
@@ -66,7 +67,7 @@ export class UserRequestPipeline {
|
||||
},
|
||||
}));
|
||||
if (decision.shouldFailRequest) {
|
||||
throw new Error(`Required pipeline stage is not registered: ${stageName}`);
|
||||
raisePipelineRequestFailure(decision, stageName);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -112,7 +113,7 @@ export class UserRequestPipeline {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
}));
|
||||
if (decision.shouldFailRequest) {
|
||||
throw error;
|
||||
raisePipelineRequestFailure(decision, stageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user