A JavaScript library that would be born if Microsoft Guidance and React had a baby.
Key Features
- React-like composability and declarative approach.
- Limited number of abstractions, minimal overhead, small code base.
- No hidden prompts, what you see is what you get.
- Low-level control, matching the way LLM actually processes the text.
- Faster learning curve due to familiar JavaScript features.
- Supports type-checking, linting, syntax highlighting, and auto-completion.
Installation
npm install salutejs yarn add salutejs pnpm add salutejs
Then set process.env.OPENAI_KEY
to your OpenAI API key.
Quick Start
This page will give you an introduction to the 80% of Salute concepts and features that you will use on a daily basis.
- Quick Start
- Advanced Examples
Simple Chat Completion
- Salute agents are sequences executing in order.
system
,user
, andassistant
define message roles.- If the sequence encounters a
gen
function, it will send the present prompt to the LLM, the returned value will be stored in the output object under the key provided as the first argument.
system`You are a helpful and terse assistant.`,
user`
I want a response to the following question:
${params.query}
Please answer the question as if experts had collaborated in writing an anonymous answer.
`,
assistant`${gen(“answer”)}`,
]
);
const result = await agent(
{ query: `How can I be more productive?` },
{ render: true } // render=true will render the chat sequence in the console
);
console.log(result);
/*
{
answer: “You can be more productive by…”,
}
*/” dir=”auto”>
import { gpt3, gen, assistant, system, user } from "salute"; const agent = gpt3( ({ params })=>[ system`You are a helpful and terse assistant.`, user` I want a response to the following question: ${params.query} Please answer the question as if experts had collaborated in writing an anonymous answer. `, assistant`${gen("answer")}`, ] ); const result = await agent( { query: `How can I be more productive?` }, { render: true } // render=true will render the chat sequence in the console ); console.log(result); /* { answer: "You can be more productive by...", } */
Creating Chat Sequences
To improve the model’s performance, let’s add another two steps to the chat sequence. The gen
function saves the output as part of the prompt for the next gen
function, making it easy to create chat sequences with minimal boilerplate.
system`You are a helpful and terse assistant.`,
user`
I want a response to the following question:
${params.query}
Don’t answer the question yet.
Name 3 world-class experts (past or present) who would be great at answering this?
`,
assistant`${gen(“expertNames”)}`,
user`
Great, now please answer the question as if these experts had collaborated in writing a joint anonymous answer.
`,
assistant`${gen(“answer”)}`,
user`Are you sure you gave a good answer? Write the answer again and fix it if necessary.`,
assistant`${gen(“fixedAnswer”)}`,
]
);
const result = await agent(
{ query: `How can I be more productive?` },
{ render: true }
);
console.log(result);
/*
{
expertNames: “Elon Musk, Bill Gates, and Jeff Bezos…”,
answer: “You can be more productive by…”,
fixedAnswer: “You can be more productive by…”
}
*/” dir=”auto”>
import { gpt3, gen, assistant, system, user } from "salute"; const agent = gpt3( ({ params })=>[ system`You are a helpful and terse assistant.`, user` I want a response to the following question: ${params.query} Don't answer the question yet. Name 3 world-class experts (past or present) who would be great at answering this? `, assistant`${gen("expertNames")}`, user` Great, now please answer the question as if these experts had collaborated in writing a joint anonymous answer. `, assistant`${gen("answer")}`, user`Are you sure you gave a good answer? Write the answer again and fix it if necessary.`, assistant`${gen("fixedAnswer")}`, ] ); const result = await agent( { query: `How can I be more productive?` }, { render: true } ); console.log(result); /* { expertNames: "Elon Musk, Bill Gates, and Jeff Bezos...", answer: "You can be more productive by...", fixedAnswer: "You can be more productive by..." } */
Creating and nesting components
Salute components are similar to React components. They are functions returning Salute primitives, such as actions (e.g. gen
, system
, user
, assistant
), AsyncGenerators, strings, or arrays and promises of these. The function will be called when sequence reaches it, so you can use the current outputs in the function.
}
async function runSQL({outputs}){
return JSON.stringify(await db.run(outputs.sqlQuery))
}
const agent = gpt3(
({ params })=>[
system`You are a helpful assistant that answers questions by writing SQL queries.`,
user`
Here is my question: ${params.query}
Here is a list of tables in the database:
—-
${
fetchTableSchemaAsAString()
/* here we pass a promise, not a function, it starts executing at the beginning of the sequence */
}
—-
Column names must be quoted with double quotes, e.g. “column_name”.
Generate a Clickhouse SQL query that answers the question above.
Return only SQL query, no other text.
`,
assistant`${gen(“sqlQuery”)}`,
user`
Here is the result of your query:
—–
${async ({outputs})=>{
return JSON.stringify(await db.run(outputs.sqlQuery))
}}
—–
Please convert the result to a text answer, so that it is easy to understand.
`,
assistant`${gen(“answer”)}`,
]
);
const result = await agent(
{ query: `How many users are there in the database?` },
{ render: true } // render=true will render the chat sequence in the console
);
console.log(result);” dir=”auto”>
import { gpt3, gen, assistant, system, user } from "salutejs"; import { db } from "a-random-sql-library"; // example of a component async function fetchTableSchemaAsAString(){ const listOfTables = await db.tables(); return listOfTables.map(table=>`Table ${table.name} has columns ${table.columns.join(", ")}`).join("n"); } async function runSQL({outputs}){ return JSON.stringify(await db.run(outputs.sqlQuery)) } const agent = gpt3( ({ params })=>[ system`You are a helpful assistant that answers questions by writing SQL queries.`, user` Here is my question: ${params.query} Here is a list of tables in the database: ---- ${ fetchTableSchemaAsAString() /* here we pass a promise, not a function, it starts executing at the beginning of the sequence */ } ---- Column names must be quoted with double quotes, e.g. "column_name". Generate a Clickhouse SQL query that answers the question above. Return only SQL query, no other text. `, assistant`${gen("sqlQuery")}`, user` Here is the result of your query: ----- ${async ({outputs})=>{ return JSON.stringify(await db.run(outputs.sqlQuery)) }} ----- Please convert the result to a text answer, so that it is easy to understand. `, assistant`${gen("answer")}`, ] ); const result = await agent( { query: `How many users are there in the database?` }, { render: true } // render=true will render the chat sequence in the console ); console.log(result);
Array.map for Chat Sequences
Salute natively supports Arrays, so you can dynamically generate chat sequences. If gen
is used inside an array, the output will be an array of generated values.
system`
Act as a prompt generator for a generative AI called “${AI_NAME}”.
${AI_NAME} AI generates images based on given prompts.
`,
user`
My query is: ${params.query}
Generate descriptions about my query, in realistic photographic style, for an Instagram post.
The answer should be one sentence long, starting directly with the description.
`,
QUESTIONS.map((item) => [
user`${item}`,
assistant`${gen(“answer”)}`
]),
]);
const result = await agent(
{ query: `A picture of a dog` },
{ render: true }
);
console.log(result);
/*
{
answer: [“Answer 1”, “Answer 2”, “Answer 3”, “Answer 4″]
}
*/” dir=”auto”>
import { gpt3, assistant, system, user, gen } from "salutejs"; const AI_NAME = "Midjourney"; const QUESTIONS = [ `Main elements with specific imagery details`, `Next, describe the environment`, `Now, provide the mood / feelings and atmosphere of the scene`, `Finally, describe the photography style (Photo, Portrait, Landscape, Fisheye, Macro) along with camera model and settings`, ]; const agent = gpt3(({ params }) => [ system` Act as a prompt generator for a generative AI called "${AI_NAME}". ${AI_NAME} AI generates images based on given prompts. `, user` My query is: ${params.query} Generate descriptions about my query, in realistic photographic style, for an Instagram post. The answer should be one sentence long, starting directly with the description. `, QUESTIONS.map((item) => [ user`${item}`, assistant`${gen("answer")}` ]), ]); const result = await agent( { query: `A picture of a dog` }, { render: true } ); console.log(result); /* { answer: ["Answer 1", "Answer 2", "Answer 3", "Answer 4"] } */
Alternatively, you can use map
function to get an array of objects.
system`
Act as a prompt generator for a generative AI called “${AI_NAME}”.
${AI_NAME} AI generates images based on given prompts.
`,
user`
My query is: ${params.query}
Generate descriptions about my query, in realistic photographic style, for an Instagram post.
The answer should be one sentence long, starting directly with the description.
`,
map(‘items’, QUESTIONS.map((item) => [
user`${item}`,
assistant`${gen(“answer”)}`
])),
]);
const result = await agent(
{ query: `A picture of a dog` },
{ render: true }
);
console.log(result);
/*
{
items: [
{ answer: “Answer 1” },
{ answer: “Answer 2” },
{ answer: “Answer 3” },
{ answer: “Answer 4″ }
]
}
*/” dir=”auto”>
import { gpt3, assistant, system, user, gen, map } from "salutejs"; const AI_NAME = "Midjourney"; const QUESTIONS = [ `Main elements with specific imagery details`, `Next, describe the environment`, `Now, provide the mood / feelings and atmosphere of the scene`, `Finally, describe the photography style (Photo, Portrait, Landscape, Fisheye, Macro) along with camera model and settings`, ]; const agent = gpt3(({ params }) => [ system` Act as a prompt generator for a generative AI called "${AI_NAME}". ${AI_NAME} AI generates images based on given prompts. `, user` My query is: ${params.query} Generate descriptions about my query, in realistic photographic style, for an Instagram post. The answer should be one sentence long, starting directly with the description. `, map('items', QUESTIONS.map((item) => [ user`${item}`, assistant`${gen("answer")}` ])), ]); const result = await agent( { query: `A picture of a dog` }, { render: true } ); console.log(result); /* { items: [ { answer: "Answer 1" }, { answer: "Answer 2" }, { answer: "Answer 3" }, { answer: "Answer 4" } ] } */
Davinci model JSON Example
Here is an example of getting the LLM to generate inference while perfectly maintaining the schema you want without any extra prompt engineering on schema or many examples. salutejs
will generate text only in the places where the gen
function is called.