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
43 changes: 43 additions & 0 deletions framework/logstore/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ func triggerMigrations(ctx context.Context, db *gorm.DB) error {
if err := migrationAddAttemptTrailColumn(ctx, db); err != nil {
return err
}
if err := migrationAddSelectedPromptColumns(ctx, db); err != nil {
return err
}
return nil
}

Expand Down Expand Up @@ -2499,3 +2502,43 @@ func migrationAddAttemptTrailColumn(ctx context.Context, db *gorm.DB) error {
return nil
}

// migrationAddSelectedPromptColumns adds selected_prompt_name, selected_prompt_version, selected_prompt_id for logs UI.
func migrationAddSelectedPromptColumns(ctx context.Context, db *gorm.DB) error {
opts := *migrator.DefaultOptions
opts.UseTransaction = true

columns := []string{"selected_prompt_name", "selected_prompt_version", "selected_prompt_id"}

m := migrator.New(db, &opts, []*migrator.Migration{{
ID: "logs_add_selected_prompt_columns",
Migrate: func(tx *gorm.DB) error {
tx = tx.WithContext(ctx)
mig := tx.Migrator()
for _, col := range columns {
if !mig.HasColumn(&Log{}, col) {
if err := mig.AddColumn(&Log{}, col); err != nil {
return err
}
}
}
return nil
},
Rollback: func(tx *gorm.DB) error {
tx = tx.WithContext(ctx)
mig := tx.Migrator()
for _, col := range columns {
if mig.HasColumn(&Log{}, col) {
if err := mig.DropColumn(&Log{}, col); err != nil {
return err
}
}
}
return nil
},
}})
err := m.Migrate()
if err != nil {
return fmt.Errorf("error while adding selected prompt columns: %s", err.Error())
}
return nil
}
3 changes: 3 additions & 0 deletions framework/logstore/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ type Log struct {
RoutingEnginesUsedStr *string `gorm:"type:varchar(255);column:routing_engines_used" json:"-"` // Comma-separated routing engines
RoutingRuleID *string `gorm:"type:varchar(255);index:idx_logs_routing_rule_id" json:"routing_rule_id"`
RoutingRuleName *string `gorm:"type:varchar(255)" json:"routing_rule_name"`
SelectedPromptName *string `gorm:"type:varchar(255)" json:"selected_prompt_name"`
SelectedPromptVersion *string `gorm:"type:varchar(64)" json:"selected_prompt_version"`
SelectedPromptID *string `gorm:"type:varchar(36)" json:"selected_prompt_id"`
UserID *string `gorm:"type:varchar(255);index:idx_logs_user_id" json:"user_id"`
TeamID *string `gorm:"type:varchar(255);index:idx_logs_team_id" json:"team_id"`
TeamName *string `gorm:"type:varchar(255)" json:"team_name"`
Expand Down
5 changes: 4 additions & 1 deletion plugins/logging/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,9 @@ func (p *LoggerPlugin) PostLLMHook(ctx *schemas.BifrostContext, result *schemas.
virtualKeyName := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceVirtualKeyName)
routingRuleID := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceRoutingRuleID)
routingRuleName := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceRoutingRuleName)
selectedPromptName := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeySelectedPromptName)
selectedPromptVersion := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeySelectedPromptVersion)
selectedPromptID := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeySelectedPromptID)
teamID := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceTeamID)
teamName := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceTeamName)
customerID := bifrost.GetStringFromContext(ctx, schemas.BifrostContextKeyGovernanceCustomerID)
Expand Down Expand Up @@ -765,7 +768,7 @@ func (p *LoggerPlugin) PostLLMHook(ctx *schemas.BifrostContext, result *schemas.
if result != nil {
latency = result.GetExtraFields().Latency
}
applyOutputFieldsToEntry(entry, selectedKeyID, selectedKeyName, virtualKeyID, virtualKeyName, routingRuleID, routingRuleName, teamID, teamName, customerID, customerName, userID, businessUnitID, businessUnitName, numberOfRetries, latency, attemptTrail)
applyOutputFieldsToEntry(entry, selectedKeyID, selectedKeyName, virtualKeyID, virtualKeyName, routingRuleID, routingRuleName, selectedPromptID, selectedPromptName, selectedPromptVersion, teamID, teamName, customerID, customerName, userID, businessUnitID, businessUnitName, numberOfRetries, latency, attemptTrail)
entry.MetadataParsed = pending.InitialData.Metadata
entry.MetadataParsed = mergeRealtimeMetadata(entry.MetadataParsed, ctx)
entry.RoutingEngineLogs = routingEngineLogs
Expand Down
10 changes: 10 additions & 0 deletions plugins/logging/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ func applyOutputFieldsToEntry(
selectedKeyID, selectedKeyName string,
virtualKeyID, virtualKeyName string,
routingRuleID, routingRuleName string,
selectedPromptID, selectedPromptName, selectedPromptVersion string,
teamID, teamName string,
customerID, customerName string,
userID string,
Expand All @@ -375,6 +376,15 @@ func applyOutputFieldsToEntry(
if routingRuleName != "" {
entry.RoutingRuleName = &routingRuleName
}
if selectedPromptID != "" {
entry.SelectedPromptID = &selectedPromptID
}
if selectedPromptName != "" {
entry.SelectedPromptName = &selectedPromptName
}
if selectedPromptVersion != "" {
entry.SelectedPromptVersion = &selectedPromptVersion
}
if teamID != "" {
entry.TeamID = &teamID
}
Expand Down
10 changes: 9 additions & 1 deletion transports/bifrost-http/handlers/prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,12 @@ func (h *PromptsHandler) createSession(ctx *fasthttp.RequestCtx) {
if len(req.ModelParams) == 0 {
req.ModelParams = version.ModelParams
}
if len(req.Variables) == 0 && len(version.Variables) > 0 {
req.Variables = make(tables.PromptVariables, len(version.Variables))
for key := range version.Variables {
req.Variables[key] = ""
}
}
} else {
// Use provided messages
for _, msg := range req.Messages {
Expand Down Expand Up @@ -904,7 +910,9 @@ func (h *PromptsHandler) updateSession(ctx *fasthttp.RequestCtx) {
session.ModelParams = req.ModelParams
session.Provider = req.Provider
session.Model = req.Model
session.Variables = req.Variables
if req.Variables != nil {
session.Variables = req.Variables
}

// Update messages
var messages []tables.TablePromptSessionMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export function PromptDeploymentsAccordionItem({
deploymentsOpen ? "min-h-0 grow overflow-hidden" : "shrink-0 grow-0",
)}
>
<AccordionTrigger data-testid="prompt-deployments-trigger" className="text-muted-foreground w-full min-w-0 shrink-0 py-3 pr-1 text-xs font-medium uppercase hover:no-underline">
<span className="min-w-0 flex-1 text-left">Deployments</span>
<AccordionTrigger data-testid="prompt-deployments-trigger" className="text-muted-foreground w-full min-w-0 shrink-0 py-3 pr-1 text-xs font-medium uppercase hover:no-underline [&[data-state=open]>svg]:rotate-180">
<span className="min-w-0 flex-1 text-left font-semibold">Deployments</span>
</AccordionTrigger>
<AccordionContent
containerClassName="data-[state=open]:flex data-[state=open]:min-h-0 data-[state=open]:flex-1 data-[state=open]:flex-col"
Expand Down
17 changes: 17 additions & 0 deletions ui/app/workspace/logs/sheets/logDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const isContainerOperation = (object: string) => {

interface LogDetailViewProps {
log: LogEntry | null;
resolvedSelectedPromptName?: string; // Current prompt name from prompt-repo when `selected_prompt_id` is set; falls back to stored log name
loading?: boolean;
handleDelete?: (log: LogEntry) => void;
onClose?: () => void;
Expand All @@ -86,6 +87,7 @@ interface LogDetailViewProps {

export function LogDetailView({
log,
resolvedSelectedPromptName,
loading = false,
handleDelete,
onClose,
Expand All @@ -100,6 +102,8 @@ export function LogDetailView({

if (!log) return null;

const selectedPromptDisplayName = resolvedSelectedPromptName ?? log.selected_prompt_name ?? "";

const isContainer = isContainerOperation(log.object);
const isPassthrough = isPassthroughOperation(log.object);
const passthroughParams = isPassthrough
Expand Down Expand Up @@ -279,6 +283,19 @@ export function LogDetailView({
/>
)}
{log.selected_key && <LogEntryDetailsView className="w-full" label="Selected Key" value={log.selected_key.name} />}
{(log.selected_prompt_id || log.selected_prompt_name || log.selected_prompt_version) && (
<LogEntryDetailsView
className="w-full"
label="Selected Prompt"
value={
<span className="break-words">
{selectedPromptDisplayName}
{selectedPromptDisplayName && log.selected_prompt_version ? " · " : ""}
{log.selected_prompt_version ? <>v{log.selected_prompt_version}</> : null}
</span>
}
/>
)}
{log.number_of_retries > 0 && (
<LogEntryDetailsView className="w-full" label="Number of Retries" value={log.number_of_retries} />
)}
Expand Down
21 changes: 16 additions & 5 deletions ui/app/workspace/logs/sheets/logDetailsSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { useGetLogByIdQuery } from "@/lib/store/apis/logsApi";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet";
import { useGetLogByIdQuery } from "@/lib/store/apis/logsApi";
import { useGetPromptQuery } from "@/lib/store/apis/promptsApi";
import type { LogEntry } from "@/lib/types/logs";
import { ChevronDown, ChevronUp, Loader2 } from "lucide-react";
import { useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { LogDetailView } from "./logDetailView";

interface LogDetailSheetProps {
Expand Down Expand Up @@ -39,8 +40,16 @@ export function LogDetailSheet({
skip: !open || !log?.id,
pollingInterval,
});

const shouldPoll = isError || fullLog?.status === "processing";

const isFullDataReady = log != null && (isError || (fullLog?.id === log.id && !isLoading));
// Prefer full log when loaded; otherwise list row — enables prompt fetch in parallel with getLogById
const selectedPromptId = log ? (fullLog?.id === log.id ? fullLog : log).selected_prompt_id : undefined;
const { data: selectedPromptData } = useGetPromptQuery(selectedPromptId ?? "", {
skip: !open || !selectedPromptId,
});

useEffect(() => {
setPollingInterval(shouldPoll ? 2000 : 0);
}, [shouldPoll]);
Expand All @@ -51,9 +60,10 @@ export function LogDetailSheet({

if (!log) return null;


// Show a loader only on the initial fetch, not during background polling refetches.
const isFullDataReady = fullLog?.id === log.id && !isLoading;
const displayLog = isFullDataReady ? fullLog : log;
const displayLog: LogEntry = isFullDataReady && fullLog ? fullLog : log;
const resolvedSelectedPromptName = selectedPromptData?.prompt?.name ?? displayLog.selected_prompt_name ?? "";
Comment thread
roroghost17 marked this conversation as resolved.

return (
<Sheet open={open} onOpenChange={onOpenChange}>
Expand All @@ -66,6 +76,7 @@ export function LogDetailSheet({
) : (
<LogDetailView
log={displayLog}
resolvedSelectedPromptName={resolvedSelectedPromptName}
handleDelete={handleDelete}
onClose={() => onOpenChange(false)}
onFilterByParentRequestId={onFilterByParentRequestId}
Expand Down
6 changes: 0 additions & 6 deletions ui/app/workspace/prompt-repo/deployments/layout.tsx

This file was deleted.

6 changes: 6 additions & 0 deletions ui/app/workspace/prompt-repo/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createFileRoute } from '@tanstack/react-router';
import PromptsPage from "./page";

export const Route = createFileRoute('/workspace/prompt-repo')({
component: PromptsPage,
})
16 changes: 10 additions & 6 deletions ui/app/workspace/prompt-repo/prompts/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use client";

import { redirect, useSearchParams } from "next/navigation";
import { useLocation, useNavigate } from "@tanstack/react-router";
import { useEffect } from "react";

export default function PromptsPage() {
const searchParams = useSearchParams();
const queryString = searchParams.toString();
redirect(`/workspace/prompt-repo${queryString ? `?${queryString}` : ""}`);
const navigate = useNavigate();
const { searchStr } = useLocation();

useEffect(() => {
navigate({ to: `/workspace/prompt-repo${searchStr}`, replace: true });
}, [navigate, searchStr]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return null;
}
2 changes: 1 addition & 1 deletion ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
validateRoutingRules
} from "@/lib/utils/celConverterRouting";
import { Plus, Save, Trash2, X } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { lazy, Suspense, useCallback, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { RuleGroupType } from "react-querybuilder";
import { toast } from "sonner";
Expand Down
22 changes: 17 additions & 5 deletions ui/components/ui/custom/celBuilder/valueEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,28 @@ import { getProviderLabel } from "@/lib/constants/logs";
import { useEffect, useState } from "react";
import { ValueEditorProps, ValueEditorType } from "react-querybuilder";

export function ValueEditor({ value, handleOnChange, operator, fieldData, type }: ValueEditorProps) {
type CELValueEditorContext = {
validateRegex?: (pattern: string) => string | null;
menuPosition?: "absolute" | "fixed";
menuPortalTarget?: HTMLElement | null;
};

export function ValueEditor({
value,
handleOnChange,
operator,
fieldData,
type,
context,
}: ValueEditorProps & { context?: CELValueEditorContext }) {
// Compute all conditions upfront before any early returns
const isArrayOperator = operator === "in" || operator === "notIn";
const isRegexOperator = operator === "matches";
const isNullOperator = operator === "null" || operator === "notNull";

// Get validateRegex from context if provided
const validateRegex: ((pattern: string) => string | null) | undefined = context?.validateRegex;
const menuPosition: "absolute" | "fixed" | undefined = context?.menuPosition;
const menuPortalTarget: HTMLElement | null | undefined = context?.menuPortalTarget;
const validateRegex = context?.validateRegex;
const menuPosition = context?.menuPosition;
const menuPortalTarget = context?.menuPortalTarget;

// Get valueEditorType, handling both string and function types
const valueEditorType =
Expand Down
3 changes: 3 additions & 0 deletions ui/lib/types/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ export interface LogEntry {
fallback_index: number;
attempt_trail?: KeyAttemptRecord[]; // Per-attempt key selection history
selected_key_id?: string | null;
selected_prompt_id?: string; // Selected prompt ID (prompts plugin)
selected_prompt_name?: string; // Resolved prompt display name (prompts plugin)
selected_prompt_version?: string; // Resolved prompt version number as string (prompts plugin)
team_name?: string;
team_id?: string;
customer_name?: string;
Expand Down
Loading