bardd's picture
Deploy Mike backend-only Space
06671aa verified
Raw History Blame Contribute Delete
4.88 kB
import type { ChatMessage, DocIndex } from "../chatTools";
import type {
AssistantRoutingContextV2,
AssistantSurface,
FocusedDocumentExcerpt,
} from "./types";
import type { RequestedAssistantMode } from "./requestedMode";
import { detectMutationIntentHint } from "./mutationHint";
export const CONTEXT_RECENT_MESSAGE_MAX = 2;
export const CONTEXT_RECENT_MESSAGE_CHAR_LIMIT = 800;
export const CONTEXT_LATEST_MESSAGE_CHAR_LIMIT = 12_000;
export const CONTEXT_FOCUSED_EXCERPT_CHAR_LIMIT = 4_000;
function truncate(value: string, max: number): string {
if (value.length <= max) return value;
return value.slice(0, max);
}
function fileTypeFor(filename: string, known?: string): string | null {
if (known && typeof known === "string") return known;
const lower = (filename || "").toLowerCase();
const ext = lower.slice(lower.lastIndexOf(".") + 1);
if (!ext || ext === lower) return null;
return ext;
}
function isEditable(fileType: string | null): boolean {
return fileType === "docx";
}
interface ContextDocInput {
documentId: string;
filename: string;
}
/**
* Build the bounded, sanitized routing context. Contains only metadata safe to
* send to a read-only router model: latest user message, at most two recent
* conversation messages (truncated), filenames/file types/editable flags, and
* optionally a focused excerpt the user pasted/quoted or selected in the UI.
*
* Never includes: signed URLs, storage paths, database rows, comments, full
* document bodies, tool results, or secrets.
*/
export function buildAssistantRoutingContext(params: {
surface: AssistantSurface;
requestedMode: RequestedAssistantMode;
messages: ChatMessage[];
docIndex: DocIndex;
displayedDocument?: ContextDocInput | null;
attachedDocuments?: ContextDocInput[];
projectDocumentCount?: number;
selectedWorkflow?: { workflowId: string; title: string } | null;
focusedDocumentExcerpt?: FocusedDocumentExcerpt | null;
confirmationPresented?: boolean;
}): AssistantRoutingContextV2 {
const {
surface,
requestedMode,
messages,
docIndex,
displayedDocument = null,
attachedDocuments = [],
projectDocumentCount = 0,
selectedWorkflow = null,
focusedDocumentExcerpt = null,
confirmationPresented = false,
} = params;
// Latest user message only.
const latestUser =
[...messages].reverse().find((m) => m.role === "user") ?? null;
const latestUserMessage = truncate(
latestUser?.content ?? "",
CONTEXT_LATEST_MESSAGE_CHAR_LIMIT,
);
// At most two recent conversation messages for reference resolution.
const recentConversation: AssistantRoutingContextV2["recentConversation"] = [];
const trimmed = messages.slice(-CONTEXT_RECENT_MESSAGE_MAX - 1);
for (const m of trimmed) {
if (m.role !== "user" && m.role !== "assistant") continue;
recentConversation.push({
role: m.role,
content: truncate(m.content ?? "", CONTEXT_RECENT_MESSAGE_CHAR_LIMIT),
});
if (recentConversation.length >= CONTEXT_RECENT_MESSAGE_MAX) break;
}
function resolveDoc(input: ContextDocInput) {
const entry = docIndex[input.documentId];
const filename = entry?.filename ?? input.filename;
const fileType = fileTypeFor(filename, entry?.file_type);
return {
documentId: input.documentId,
filename,
fileType,
editable: isEditable(fileType),
revisionId: entry?.version_id ?? null,
};
}
const displayedDocumentResolved = displayedDocument
? resolveDoc(displayedDocument)
: null;
const attachedDocumentsResolved = attachedDocuments.map(resolveDoc);
// Focused excerpt only when pasted/quoted by the user or selected in UI,
// capped, never scanned from a document body.
let focused: FocusedDocumentExcerpt | null = null;
if (focusedDocumentExcerpt && focusedDocumentExcerpt.text) {
focused = {
documentId: focusedDocumentExcerpt.documentId,
text: truncate(
focusedDocumentExcerpt.text,
CONTEXT_FOCUSED_EXCERPT_CHAR_LIMIT,
),
source: focusedDocumentExcerpt.source,
};
}
return {
schemaVersion: 2,
surface,
requestedMode,
currentDate: new Date().toISOString().slice(0, 10),
latestUserMessage,
recentConversation,
displayedDocument: displayedDocumentResolved,
attachedDocuments: attachedDocumentsResolved,
projectDocumentCount,
selectedWorkflow,
focusedDocumentExcerpt: focused,
mutationIntentHint: detectMutationIntentHint(latestUserMessage),
confirmationPresented,
};
}