@langchain/anthropic
Version:
Anthropic integrations for LangChain.js
102 lines (98 loc) • 4.02 kB
JavaScript
import { XMLBuilder } from "fast-xml-parser";
import { PromptTemplate } from "@langchain/core/prompts";
export const DEFAULT_TOOL_SYSTEM_PROMPT =
/* #__PURE__ */ PromptTemplate.fromTemplate(`In this environment you have access to a set of tools you can use to answer the user's question.
You may call them like this:
<function_calls>
<invoke>
<tool_name>$TOOL_NAME</tool_name>
<parameters>
<$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>
...
</parameters>
</invoke>
</function_calls>
Here are the tools available:
{tools}
If the schema above contains a property typed as an enum, you must only return values matching an allowed value for that enum.`);
export function formatAsXMLRepresentation(tool) {
const builder = new XMLBuilder();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const toolParamProps = tool.function.parameters?.properties;
const parameterXml = Object.keys(toolParamProps)
.map((key) => {
const parameterData = toolParamProps[key];
let xml = `<parameter>
<name>${key}</name>
<type>${parameterData.type}</type>`;
if (parameterData.description) {
xml += `\n<description>${parameterData.description}</description>`;
}
if (parameterData.type === "array" && parameterData.items) {
xml += `\n<items>${builder.build(parameterData.items.properties)}</items>`;
}
if (parameterData.properties) {
xml += `\n<properties>\n${builder.build(parameterData.properties)}\n</properties>`;
}
return `${xml}\n</parameter>`;
})
.join("\n");
return `<tool_description>
<tool_name>${tool.function.name}</tool_name>
<description>${tool.function.description}</description>
<parameters>
${parameterXml}
</parameters>
</tool_description>`;
}
export function fixArrayXMLParameters(schema,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
xmlParameters
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const fixedParameters = {};
for (const key of Object.keys(xmlParameters)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const schemaType = schema.properties[key].type;
// Crawl for lists indistinguishable from single items
if (schema.properties && schema.properties[key] && schemaType === "array") {
const value = xmlParameters[key];
if (Array.isArray(value)) {
fixedParameters[key] = value;
}
else if (typeof value === "string") {
if (value.startsWith("[") && value.endsWith("]")) {
fixedParameters[key] = JSON.parse(value);
}
else {
fixedParameters[key] = value.split(",");
}
}
else {
fixedParameters[key] = [value];
}
// Crawl for objects like {"item": "my string"} that should really just be "my string"
if (schemaType !== "object" &&
typeof xmlParameters[key] === "object" &&
!Array.isArray(xmlParameters[key]) &&
Object.keys(xmlParameters[key]).length === 1) {
// eslint-disable-next-line prefer-destructuring
fixedParameters[key] = Object.values(xmlParameters[key])[0];
}
}
else if (typeof xmlParameters[key] === "object" &&
xmlParameters[key] !== null) {
fixedParameters[key] = fixArrayXMLParameters({
...schema.properties[key],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
definitions: schema.definitions,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}, xmlParameters[key]);
}
else {
fixedParameters[key] = xmlParameters[key];
}
}
return fixedParameters;
}