UNPKG

jest-ai

Version:

Custom jest matchers for testing AI applications

2 lines (1 loc) 5.46 kB
"use strict";var e=require("@langchain/openai"),t=require("openai"),s=require("@langchain/core/prompts"),n=require("@langchain/core/output_parsers");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o,a,r=i(t);function c(e,t,s){if(t.every((e=>"string"==typeof e))){const n=t=>e.findIndex((e=>e.function.name===t))>-1;return s?t.every(n):t.some(n)}if(function(e){return e.every((e=>"string"==typeof e.name&&"string"==typeof e.arguments))}(t)){const n=t=>e.findIndex((e=>t.name===e.function.name&&t.arguments===e.function.arguments))>-1;return s?t.every(n):t.some(n)}return!1}class u{constructor(){this.embedding=new e.OpenAIEmbeddings}static getInstance(){return u.instance||(u.instance=new u),u.instance}async compareEmbeddings(e,t){const s=await Promise.all([u.instance.embedding.embedQuery(e),u.instance.embedding.embedQuery(t)]);return function(e,t){let s=0,n=0,i=0;for(let o=0;o<e.length;o++)s+=e[o]*t[o],n+=e[o]*e[o],i+=t[o]*t[o];return s/(Math.sqrt(n)*Math.sqrt(i))}(s[0],s[1])}}function l(){const t=u.getInstance();return{semantic:async function(e,s,n){return function(e,t){const s=t>a.HIGH,n=t>a.MID&&t<a.HIGH,i=t<a.LOW;switch(e){case o.HIGH:return s;case o.MID:return n||s;case o.LOW:return i||n||s;default:return!1}}(e,await t.compareEmbeddings(s,n))},absolute:function(e,t){return e===t},zodSchema:function(e,t){try{return e.parse(JSON.parse(t))}catch(e){return!1}},tools:async function(e,t,s){const n=await t();if(!n.choices[0]?.message)throw new Error("No response to read tool calls from");const i=n.choices[0]?.message.tool_calls;return!!i&&c(i,e,s)},assistantTools:async function(e,t,s){const n=new r.default,i=await n.beta.threads.runs.poll(t.thread_id,t.id);if("requires_action"!==i.status||!i.required_action)throw new Error(`Run entered terminal state "${i.status}" that did not require action`);if("submit_tool_outputs"!==i.required_action.type)throw new Error(`Run required action type is "${i.required_action.type}" instead of "submit_tool_outputs"`);const o=i.required_action.submit_tool_outputs.tool_calls;return!!o&&c(o,e,s)},satisfiesStatement:async function(t,i,o="gpt-4-turbo"){const a=new e.ChatOpenAI({model:o,temperature:0}),r=s.ChatPromptTemplate.fromMessages([s.SystemMessagePromptTemplate.fromTemplate(`\n You are a comprehension utility that confirms whether or not a given statement is true within some context.\n The user will provide a statement. Using ONLY the provided context, you will determine if the statement is true or false.\n The context that you will analyse is provided below between the "---" characters.\n You will respond with only the text "true" or "false" and with no other characters or words.\n If the answer to the truthiness of the statement cannot be found within the context, respond with "false".\n ONLY USE INFORMATION FOUND WITHIN THE CONTEXT TO ANSWER THE QUESTION\n ---\n ${i}\n ---\n `),s.HumanMessagePromptTemplate.fromTemplate(`Within the provided context, is the following statement true or false: ${t}`)]).pipe(a).pipe(new n.StringOutputParser);return"true"===await r.invoke({})}}}async function p(e,t){const s=l();return await s.semantic(o.MID,t,e)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected: ${this.utils.printExpected(t)} to semantically match ${this.utils.printReceived(e)}`,pass:!1}}async function d(e,t){const s=l();return await s.tools(t,e,!0)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected all tools: ${this.utils.printExpected(t)} to have been used but they were not`,pass:!1}}async function m(e,t){const s=l();return await s.tools(t,e,!1)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected some tools: ${this.utils.printExpected(t)}\n to have been used, but they were not`,pass:!1}}async function h(e,t){const s=l();return await s.assistantTools(t,e,!0)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected all tools: ${this.utils.printExpected(t)} to have been used but they were not`,pass:!1}}async function f(e,t){const s=l();return await s.assistantTools(t,e,!1)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected all tools: ${this.utils.printExpected(t)} to have been used but they were not`,pass:!1}}async function w(e,t){const s=l();return await s.satisfiesStatement(t,e)?{message:()=>`Expected: ${this.utils.printExpected(t)}\nReceived: ${this.utils.printReceived(e)}`,pass:!0}:{message:()=>`Expected: ${this.utils.printExpected(e)} to satisfy the statement: ${this.utils.printReceived(t)}`,pass:!1}}!function(e){e.LOW="low",e.MID="mid",e.HIGH="high"}(o||(o={})),function(e){e[e.LOW=.7]="LOW",e[e.MID=.75]="MID",e[e.HIGH=.85]="HIGH"}(a||(a={}));var g=Object.freeze({__proto__:null,toSemanticallyMatch:p,toHaveUsedAllTools:d,toHaveUsedSomeTools:m,toHaveUsedAllAssistantTools:h,toHaveUsedSomeAssistantTools:f,toSatisfyStatement:w});exports.extensions=g,exports.toHaveUsedAllAssistantTools=h,exports.toHaveUsedAllTools=d,exports.toHaveUsedSomeAssistantTools=f,exports.toHaveUsedSomeTools=m,exports.toSatisfyStatement=w,exports.toSemanticallyMatch=p;