Refactor calculating score. Add sort node for vanity

This commit is contained in:
William Jeynes
2026-02-12 23:46:00 +00:00
parent b06c08daab
commit 7fe63d6a98
6 changed files with 56 additions and 30 deletions
+5 -1
View File
@@ -9,6 +9,7 @@ import { ragasMetrics } from "./nodes/ragasMetrics";
import { produceRanking } from "./nodes/produceRanking";
import { createModelNode } from "./nodes/model";
import { loopEndConditional } from "./conditionals/loop_end";
import { sort } from "./nodes/sort";
const triggerEventToolNode = createToolNode(triggerEventToolsByName);
@@ -34,6 +35,7 @@ const agent = new StateGraph(MessagesState)
.addNode("relationModel", relationModel)
.addNode(produceRanking.name, produceRanking)
.addNode(sort.name, sort)
.addEdge(START, normalizationSetup.name)
.addEdge(normalizationSetup.name, "normalisationModel")
@@ -52,8 +54,10 @@ const agent = new StateGraph(MessagesState)
.addEdge("relationModel", produceRanking.name)
// @ts-expect-error
.addConditionalEdges(produceRanking.name, loopEndConditional, [verificationSetup.name, END])
.addConditionalEdges(produceRanking.name, loopEndConditional, [verificationSetup.name, sort.name])
.addEdge(sort.name, END)
.compile();
export {agent}
+1 -1
View File
@@ -7,7 +7,7 @@ export const loopEndConditional: ConditionalEdgeRouter<typeof MessagesState, Str
const triggerEventsIndex = state.proposedTriggerEventIndex;
if (triggerEventsIndex == triggerEvents.length-1) {
return END
return "sort"
}
else {
return "verificationSetup"
+29 -19
View File
@@ -2,49 +2,59 @@ import { GraphNode } from "@langchain/langgraph";
import { MessagesState } from "../state";
import { BaseMessage } from "@langchain/core/messages";
type Priority = keyof typeof mapping;
//TODO: Each of these might need different weights
const keys = ["CONFIDENCE", "RAGAS", "RELATION"];
const mapping = {
VERYHIGH: 1.0,
HIGH: 0.75,
MEDIUM: 0.5,
LOW: 0.25,
VERYLOW: 0.0
VERYLOW: 0.0,
} as const;
function mapResponse(value: string): number {
const upper = value.toUpperCase() as Priority;
type Priority = keyof typeof mapping;
if (upper in mapping) {
return mapping[upper];
}
function mapResponse(value: string | undefined | null): number {
if (!value) return 0;
return 0;
const trimmed = value.trim();
const num = parseFloat(trimmed);
// If number, return it
if (!isNaN(num)) return num;
// Otherwise, map to value
const upper = trimmed.toUpperCase() as Priority;
return mapping[upper] ?? 0;
}
function getLastMessageContaining(
messages: BaseMessage[],
searchString: string
): string {
): string | null {
for (let i = messages.length - 1; i >= 0; i--) {
const content = messages[i].content;
if (typeof content === "string" && content.includes(searchString)) {
return content;
}
}
return "";
return null;
}
export const produceRanking: GraphNode<typeof MessagesState> = async (state) => {
//TODO: what should these weights be
let conf = getLastMessageContaining(state.messages, "CONFIDENCE")?.split(":")[1] //TODO: we can better error handle here
let ragas = getLastMessageContaining(state.messages, "RAGAS")?.split(":")[1] //TODO: we can genericify this too surely
let rel = getLastMessageContaining(state.messages, "RELATION")?.split(":")[1]
// Extract and map values
const values = keys.map((key) => {
const msg = getLastMessageContaining(state.messages, key);
const part = msg?.split(":").at(1);
return mapResponse(part);
});
let result = mapResponse(conf) * Number.parseFloat(ragas) * mapResponse(rel)
let current = state.proposedTriggerEvent;
// Multiply!
const result = values.reduce((acc, val) => acc * val, 1);
const current = state.proposedTriggerEvent;
current[state.proposedTriggerEventIndex].score = result;
return { proposedTriggerEvent: current };
};
return { proposedTriggerEvent: current };
};
-2
View File
@@ -8,8 +8,6 @@ export const ragasMetrics: GraphNode<typeof MessagesState> = async (state) => {
const answer = state.proposedTriggerEvent[state.proposedTriggerEventIndex].Event
const contexts = state.proposedTriggerEvent[state.proposedTriggerEventIndex].context?.split("^^^") ?? []
console.log(contexts)
const results = await evaluateWithRagas({question, answer, contexts})
return {
+20
View File
@@ -0,0 +1,20 @@
import { GraphNode } from "@langchain/langgraph";
import { MessagesState } from "../state";
import { AIMessage } from "@langchain/core/messages";
export const sort: GraphNode<typeof MessagesState> = async (state) => {
//not sure which will be better from API, just do both
let current = state.proposedTriggerEvent;
current.sort((a, b) => ((b.score as number) ?? 0) - ((a.score as number) ?? 0));
const displayVersion = current.map((item) => ({
event: item.Event,
reasoningWhyRelevant: item.ReasoningWhyRelevant,
score: item.score ?? 0,
}));
let message = new AIMessage(JSON.stringify(displayVersion))
return { proposedTriggerEvent: current, messages: [message] };
};
+1 -7
View File
@@ -1,12 +1,6 @@
import {
StateGraph,
StateSchema,
MessagesValue,
ReducedValue,
GraphNode,
ConditionalEdgeRouter,
START,
END,
} from "@langchain/langgraph";
import { z } from "zod/v4";
@@ -17,7 +11,7 @@ export const ProposedTriggerEvent = z.object({
Url: z.url(),
IsItselfDisinformation: z.boolean(),
context: z.string().optional(),
score: z.number().optional
score: z.number().optional()
})
export const ProposedTriggerEventArray = z.array(ProposedTriggerEvent);