-
Notifications
You must be signed in to change notification settings - Fork 518
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial PR for acuvity portkey integration.
- Loading branch information
1 parent
58c6eaa
commit 2455849
Showing
4 changed files
with
846 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import * as jose from 'jose'; | ||
import { Extraction, Textualdetection, TextualdetectionType } from './model.js'; | ||
|
||
export interface GuardResult { | ||
matched: boolean; | ||
guardName: GuardName; | ||
threshold: string; | ||
actualValue: number; | ||
matchCount: number; | ||
matchValues: string[]; | ||
} | ||
|
||
export class GuardName { | ||
private constructor(private readonly name: string) {} | ||
|
||
// Static instances | ||
public static readonly PROMPT_INJECTION = new GuardName('PROMPT_INJECTION'); | ||
public static readonly JAIL_BREAK = new GuardName('JAIL_BREAK'); | ||
public static readonly MALICIOUS_URL = new GuardName('MALICIOUS_URL'); | ||
public static readonly TOXIC = new GuardName('TOXIC'); | ||
public static readonly BIASED = new GuardName('BIASED'); | ||
public static readonly HARMFUL_CONTENT = new GuardName('HARMFUL_CONTENT'); | ||
public static readonly LANGUAGE = new GuardName('LANGUAGE'); | ||
public static readonly PII_DETECTOR = new GuardName('PII_DETECTOR'); | ||
public static readonly SECRETS_DETECTOR = new GuardName('SECRETS_DETECTOR'); | ||
public static readonly KEYWORD_DETECTOR = new GuardName('KEYWORD_DETECTOR'); | ||
|
||
public toString(): string { | ||
return this.name; | ||
} | ||
|
||
public equals(other: GuardName): boolean { | ||
return this.name === other.name; | ||
} | ||
} | ||
|
||
export function getApexUrlFromToken(token: string): string | null { | ||
try { | ||
const decodedToken = jose.decodeJwt(token); | ||
return decodedToken?.opaque?.['apex-url'] || null; | ||
} catch (error) { | ||
return null; | ||
} | ||
} | ||
|
||
export class ResponseHelper { | ||
/** | ||
* Evaluates a check condition using guard name and threshold. | ||
* | ||
* @param extraction - Provides all the extractions based on the detection engine | ||
* @param guardName - The name of the guard to evaluate | ||
* @param threshold - The threshold value to compare against | ||
* @param matchName - The match name for the guard | ||
* @returns GuardResult with TRUE if condition met, False if not met | ||
*/ | ||
public evaluate( | ||
extraction: Extraction, | ||
guardName: GuardName, | ||
threshold: number, | ||
matchName?: string | ||
): GuardResult { | ||
let exists = false; | ||
let value = 0.0; | ||
let matchCount = 0; | ||
let matchValues: string[] = []; | ||
|
||
try { | ||
if ( | ||
guardName.equals(GuardName.PROMPT_INJECTION) || | ||
guardName.equals(GuardName.JAIL_BREAK) || | ||
guardName.equals(GuardName.MALICIOUS_URL) | ||
) { | ||
[exists, value] = this.getGuardValue( | ||
extraction.exploits, | ||
guardName.toString() | ||
); | ||
} else if ( | ||
guardName.equals(GuardName.TOXIC) || | ||
guardName.equals(GuardName.BIASED) || | ||
guardName.equals(GuardName.HARMFUL_CONTENT) | ||
) { | ||
const prefix = `content/${guardName}`; | ||
[exists, value] = this.getGuardValue(extraction.topics, prefix); | ||
} else if (guardName.equals(GuardName.LANGUAGE)) { | ||
if (matchName) { | ||
[exists, value] = this.getGuardValue(extraction.languages, matchName); | ||
} else if (extraction.languages) { | ||
exists = Object.keys(extraction.languages).length > 0; | ||
value = 1.0; | ||
} | ||
} else if (guardName.equals(GuardName.PII_DETECTOR)) { | ||
[exists, value, matchCount, matchValues] = this.getTextDetections( | ||
extraction.piIs, | ||
threshold, | ||
TextualdetectionType.Pii, | ||
extraction.detections, | ||
matchName | ||
); | ||
} else if (guardName.equals(GuardName.SECRETS_DETECTOR)) { | ||
[exists, value, matchCount, matchValues] = this.getTextDetections( | ||
extraction.secrets, | ||
threshold, | ||
TextualdetectionType.Secret, | ||
extraction.detections, | ||
matchName | ||
); | ||
} else if (guardName.equals(GuardName.KEYWORD_DETECTOR)) { | ||
[exists, value, matchCount, matchValues] = this.getTextDetections( | ||
extraction.keywords, | ||
threshold, | ||
TextualdetectionType.Keyword, | ||
extraction.detections, | ||
matchName | ||
); | ||
} | ||
|
||
const matched = exists && value >= threshold; | ||
|
||
return { | ||
matched, | ||
guardName, | ||
threshold: threshold.toString(), | ||
actualValue: value, | ||
matchCount, | ||
matchValues, | ||
}; | ||
} catch (e) { | ||
throw new Error( | ||
`Error in evaluation: ${e instanceof Error ? e.message : String(e)}` | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the guard value from a lookup object | ||
*/ | ||
private getGuardValue( | ||
lookup: Record<string, number> | undefined, | ||
key: string | ||
): [boolean, number] { | ||
if (!lookup || !(key in lookup)) { | ||
return [false, 0.0]; | ||
} | ||
return [true, lookup[key]]; | ||
} | ||
|
||
/** | ||
* Gets text detection values | ||
*/ | ||
private getTextDetections( | ||
lookup: Record<string, number> | undefined, | ||
threshold: number, | ||
detectionType: TextualdetectionType, | ||
detections: Textualdetection[] | undefined, | ||
matchName?: string | ||
): [boolean, number, number, string[]] { | ||
if (matchName) { | ||
if (!detections) { | ||
return [false, 0.0, 0, []]; | ||
} | ||
|
||
const textMatches = detections | ||
.filter( | ||
(d): d is Textualdetection & { score: number } => | ||
d.type === detectionType && | ||
d.name === matchName && | ||
d.score !== null && | ||
typeof d.score === 'number' && | ||
d.score >= threshold | ||
) | ||
.map((d) => d.score); | ||
|
||
const count = textMatches.length; | ||
|
||
if (count === 0 && lookup && matchName in lookup) { | ||
const lookupValue = lookup[matchName]; | ||
if (typeof lookupValue === 'number') { | ||
return [true, lookupValue, 1, [matchName]]; | ||
} | ||
} | ||
|
||
if (count === 0) { | ||
return [false, 0.0, 0, []]; | ||
} | ||
|
||
const maxScore = Math.max(...textMatches); | ||
return [true, maxScore, count, [matchName]]; | ||
} | ||
|
||
const exists = !!lookup && Object.keys(lookup).length > 0; | ||
return [ | ||
exists, | ||
exists ? 1.0 : 0.0, | ||
lookup ? Object.keys(lookup).length : 0, | ||
lookup ? Object.keys(lookup) : [], | ||
]; | ||
} | ||
} |
Oops, something went wrong.