Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions apps/api/src/handlers/slack/events/auto-route-fallback.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions apps/api/src/handlers/slack/events/auto-route-fallback.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SlackInstallation, SlackUserMapping } from '@roomote/db/server';
import {
showTaskConfiguration,
SLACK_ROUTING_UNAVAILABLE_NOTICE,
type SlackEvent,
type SlackNotifier,
type StartAutoRoutedSlackTaskResult,
Expand Down Expand Up @@ -54,6 +55,10 @@ export async function showManualPickerForAutoRouteFallback(params: {
: {}),
};

const routingFailedFromException =
params.result.status === 'not_started' &&
params.result.routingFallback?.cause === 'exception';

await showTaskConfiguration({
event,
slackInstallation: params.slackInstallation as SlackInstallation,
Expand All @@ -62,6 +67,9 @@ export async function showManualPickerForAutoRouteFallback(params: {
skipRouting: true,
skipMcpSetupSuggestion: true,
processingReactionName: params.processingReactionName,
...(routingFailedFromException
? { routingFailureNoticeText: SLACK_ROUTING_UNAVAILABLE_NOTICE }
: {}),
});

return true;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cloud-agents/src/server/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type {
RoutingResult,
PlatformAnswerResult,
RoutingDecision,
RoutingFallbackCause,
FollowUpIntent,
FollowUpClassification,
} from './types';
Expand Down
8 changes: 8 additions & 0 deletions packages/cloud-agents/src/server/router/router-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ async function runRoutingDecision(
decision: {
status: 'fallback',
reason: built.fallbackReason,
cause: 'model_decision',
},
phase: responseResult.phase ?? 'fallback',
model: routingModel,
Expand Down Expand Up @@ -408,6 +409,7 @@ async function runRoutingDecision(
status: 'fallback',
reason:
error instanceof Error ? error.message : 'Unknown routing error',
cause: 'exception',
},
phase: 'fallback',
model: routingModel,
Expand Down Expand Up @@ -499,6 +501,7 @@ export async function routeTask(
status: 'fallback',
reason:
'Meta question answer was unavailable, and normal routing could not be resolved.',
cause: 'model_decision',
};
fallbackDecision.debug = {
phase: 'fallback',
Expand All @@ -513,6 +516,7 @@ export async function routeTask(
sourceType: context.source.type,
model,
phase: 'fallback',
cause: fallbackDecision.cause,
toolsUsed,
needsExternalLookup,
confidence: null,
Expand Down Expand Up @@ -566,6 +570,7 @@ export async function routeTask(
sourceType: context.source.type,
model,
phase,
cause: decision.cause ?? 'model_decision',
toolsUsed,
needsExternalLookup,
confidence: null,
Expand All @@ -588,6 +593,7 @@ export async function routeGitHubTask(
return {
status: 'fallback',
reason: 'routeGitHubTask requires a GitHub routing context.',
cause: 'exception',
};
}

Expand Down Expand Up @@ -647,6 +653,7 @@ export async function routeGitHubTask(
sourceType: context.source.type,
model: routingModel,
phase: 'fallback',
cause: 'exception',
toolsUsed: [],
needsExternalLookup: null,
confidence: null,
Expand All @@ -658,6 +665,7 @@ export async function routeGitHubTask(
return {
status: 'fallback',
reason,
cause: 'exception',
debug: {
phase: 'fallback',
toolsUsed: [],
Expand Down
23 changes: 21 additions & 2 deletions packages/cloud-agents/src/server/router/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,24 @@ export interface PlatformAnswerResult {
debug?: RoutingDebugInfo;
}

/**
* Why a routing attempt ended in fallback. `model_decision` means the router
* ran but declined to pick (ambiguous request, unmapped workspace);
* `exception` means the routing infrastructure itself failed (provider error,
* timeout) and surfaces should tell the user routing is unavailable rather
* than silently showing the manual picker. Absent means `model_decision`.
*/
export type RoutingFallbackCause = 'exception' | 'model_decision';

export type RoutingDecision =
| { status: 'routed'; result: RoutingResult }
| { status: 'platform_answer'; result: PlatformAnswerResult }
| { status: 'fallback'; reason: string; debug?: RoutingDebugInfo };
| {
status: 'fallback';
reason: string;
cause?: RoutingFallbackCause;
debug?: RoutingDebugInfo;
};

export interface GitHubRoutingResult {
reasoning: string;
Expand All @@ -233,7 +247,12 @@ export interface GitHubRoutingResult {

export type GitHubRoutingDecision =
| { status: 'routed'; result: GitHubRoutingResult }
| { status: 'fallback'; reason: string; debug?: RoutingDebugInfo };
| {
status: 'fallback';
reason: string;
cause?: RoutingFallbackCause;
debug?: RoutingDebugInfo;
};

export interface WorkspaceResponse {
workspaceValue: string;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading