fix(llm.gblib): Tool fix.
This commit is contained in:
parent
66ad2d3ee1
commit
63efa588a8
9 changed files with 92 additions and 47 deletions
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
|
@ -14,7 +14,6 @@
|
|||
"NODE_NO_WARNINGS":"1"
|
||||
},
|
||||
"args": [
|
||||
"--max-old-space-size 5120",
|
||||
"--no-deprecation",
|
||||
"--loader ts-node/esm",
|
||||
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
||||
|
|
|
@ -577,10 +577,10 @@ export class GBVMService extends GBService {
|
|||
|
||||
// Transfers auto variables into global object.
|
||||
|
||||
for(__indexer in this.variables) {
|
||||
global[__indexer] = this.variables[__indexer];
|
||||
}
|
||||
|
||||
for (const key of Object.keys(this.variables)) {
|
||||
global[key] = this.variables[key];
|
||||
console.log('Defining global variable: ' + key);
|
||||
}
|
||||
|
||||
// Defines local utility BASIC functions.
|
||||
|
||||
|
@ -805,21 +805,22 @@ export class GBVMService extends GBService {
|
|||
const propertiesExp = propertiesText[i];
|
||||
const t = getType(propertiesExp[2]);
|
||||
let element;
|
||||
const description = propertiesExp[4]?.trim();
|
||||
|
||||
if (t === 'enum') {
|
||||
const list = propertiesExp[2] as any;
|
||||
element = z.enum(list.split(','));
|
||||
} else if (t === 'string') {
|
||||
element = z.string();
|
||||
element = z.string({description:description});
|
||||
} else if (t === 'object') {
|
||||
element = z.string(); // Assuming 'object' is represented as a string here
|
||||
element = z.string({description:description}); // Assuming 'object' is represented as a string here
|
||||
} else if (t === 'number') {
|
||||
element = z.number();
|
||||
element = z.number({description:description});
|
||||
} else {
|
||||
GBLog.warn(`Element type invalid specified on .docx: ${propertiesExp[0]}`);
|
||||
}
|
||||
|
||||
element['description'] = propertiesExp[4]?.trim(); // Assuming description is in the 4th index
|
||||
|
||||
element['type'] = t;
|
||||
properties[propertiesExp[1].trim()] = element;
|
||||
}
|
||||
|
@ -829,7 +830,7 @@ export class GBVMService extends GBService {
|
|||
function: {
|
||||
name: mainName,
|
||||
description: description ? description : '',
|
||||
parameters: zodToJsonSchema(z.object(properties))
|
||||
schema: zodToJsonSchema(z.object(properties))
|
||||
},
|
||||
arguments: propertiesText.reduce((acc, prop) => {
|
||||
acc[prop[1].trim()] = prop[3]?.trim(); // Assuming value is in the 3rd index
|
||||
|
@ -1049,7 +1050,7 @@ export class GBVMService extends GBService {
|
|||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||
);
|
||||
|
||||
let variables = [];
|
||||
let variables = {};
|
||||
|
||||
// These variables will be automatically be available as normal BASIC variables.
|
||||
|
||||
|
@ -1090,7 +1091,7 @@ export class GBVMService extends GBService {
|
|||
const botId = min.botId;
|
||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbdialog`);
|
||||
const gbdialogPath = urlJoin(process.cwd(), 'work', path);
|
||||
const scriptPath = urlJoin(gbdialogPath, `${text}.js`);
|
||||
const scriptFilePath = urlJoin(gbdialogPath, `${text}.js`);
|
||||
|
||||
let code = min.sandBoxMap[text];
|
||||
const channel = step ? step.context.activity.channelId : 'web';
|
||||
|
@ -1148,7 +1149,7 @@ export class GBVMService extends GBService {
|
|||
context: 'sandbox'
|
||||
}
|
||||
});
|
||||
const s = new VMScript(code, { filename: scriptPath });
|
||||
const s = new VMScript(code, { filename: scriptFilePath });
|
||||
result = vm1.run(s);
|
||||
});
|
||||
})();
|
||||
|
@ -1167,16 +1168,17 @@ export class GBVMService extends GBService {
|
|||
min: 0,
|
||||
max: 0,
|
||||
debug: debug,
|
||||
debuggerport: GBVMService.DEBUGGER_PORT,
|
||||
// debuggerport: GBVMService.DEBUGGER_PORT,
|
||||
botId: botId,
|
||||
cpu: 100,
|
||||
memory: 50000,
|
||||
time: 60 * 60 * 24 * 14,
|
||||
cwd: scriptPath,
|
||||
cwd: gbdialogPath,
|
||||
script: runnerPath
|
||||
|
||||
});
|
||||
|
||||
result = await run(code, { filename: scriptPath, sandbox: sandbox });
|
||||
result = await run(code, Object.assign( sandbox, { filename: scriptFilePath}));
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||
|
|
|
@ -118,7 +118,6 @@ const systemVariables = [
|
|||
'valueOf'
|
||||
];
|
||||
|
||||
|
||||
export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||
limits = Object.assign(
|
||||
{
|
||||
|
@ -140,8 +139,14 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
|||
let stderrCache = '';
|
||||
|
||||
const run = async (code: any, scope: any) => {
|
||||
// Configure environment variables
|
||||
const env = Object.assign({}, process.env, {
|
||||
NODE_ENV: 'production',
|
||||
NODE_OPTIONS: '' // Clear NODE_OPTIONS if needed
|
||||
});
|
||||
|
||||
const childProcess = spawn(
|
||||
'cpulimit',
|
||||
'/usr/bin/cpulimit',
|
||||
[
|
||||
'-ql',
|
||||
limits.cpu,
|
||||
|
@ -153,7 +158,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
|||
limits.script,
|
||||
ref
|
||||
],
|
||||
{ cwd: limits.cwd, shell: false }
|
||||
{ cwd: limits.cwd, shell: true, env: env }
|
||||
);
|
||||
|
||||
childProcess.stdout.on('data', data => {
|
||||
|
@ -186,7 +191,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
|||
|
||||
// Only attach if called by debugger/run.
|
||||
|
||||
if (GBServer.globals.debuggers[limits.botId]) {
|
||||
if (limits.debug) {
|
||||
const debug = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
CDP(async client => {
|
||||
|
@ -212,7 +217,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
|||
});
|
||||
}
|
||||
GBServer.globals.debuggers[limits.botId].scope = variablesText;
|
||||
GBLogEx.info(min,`Breakpoint variables: ${variablesText}`); // (zero-based)
|
||||
GBLogEx.info(min, `Breakpoint variables: ${variablesText}`); // (zero-based)
|
||||
// Processes breakpoint hits.
|
||||
|
||||
if (hitBreakpoints.length >= 1) {
|
||||
|
|
|
@ -26,10 +26,13 @@ const server = net1.createServer(socket => {
|
|||
const buffer = [];
|
||||
|
||||
const sync = async () => {
|
||||
|
||||
const request = buffer.join('').toString();
|
||||
console.log(request);
|
||||
if (request.includes('\n')) {
|
||||
try {
|
||||
const { code, scope } = JSON.parse(request);
|
||||
|
||||
const result = await evaluate(code, {
|
||||
...scope,
|
||||
module: null
|
||||
|
@ -45,6 +48,11 @@ const server = net1.createServer(socket => {
|
|||
}
|
||||
}
|
||||
};
|
||||
socket.on('error', err => {
|
||||
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
|
||||
socket.on('data', data => {
|
||||
buffer.push(data);
|
||||
|
|
|
@ -39,6 +39,7 @@ import { ChatGeneration, Generation } from '@langchain/core/outputs';
|
|||
import {
|
||||
AIMessagePromptTemplate,
|
||||
ChatPromptTemplate,
|
||||
SystemMessagePromptTemplate,
|
||||
HumanMessagePromptTemplate,
|
||||
MessagesPlaceholder
|
||||
} from '@langchain/core/prompts';
|
||||
|
@ -72,6 +73,7 @@ import {
|
|||
} from 'langchain/chains/sql_db';
|
||||
import { GBUtil } from '../../../src/util.js';
|
||||
import { z } from 'zod';
|
||||
import zodToJsonSchema from 'zod-to-json-schema';
|
||||
export interface CustomOutputParserFields {}
|
||||
export type ExpectedOutput = any;
|
||||
|
||||
|
@ -323,25 +325,38 @@ export class ChatServices {
|
|||
|
||||
let tools = await ChatServices.getTools(min);
|
||||
let toolsAsText = ChatServices.getToolsAsText(tools);
|
||||
let openaiTools = tools.map(tool => convertToOpenAITool(tool, { strict: true }));
|
||||
|
||||
function updateFields(schemas) {
|
||||
schemas.forEach(schema => {
|
||||
|
||||
if (schema.function && schema.function.parameters) {
|
||||
delete schema.function.strict;
|
||||
schema.function.parameters.additionalProperties = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
updateFields(openaiTools);
|
||||
|
||||
const modelWithTools = model.bind({
|
||||
tools: tools.map(convertToOpenAITool)
|
||||
tools: openaiTools
|
||||
});
|
||||
|
||||
const questionGeneratorTemplate = ChatPromptTemplate.fromMessages([
|
||||
AIMessagePromptTemplate.fromTemplate(
|
||||
SystemMessagePromptTemplate.fromTemplate(
|
||||
`
|
||||
Answer the question without calling any tool, but if there is a need to call:
|
||||
You have access to the following set of tools.
|
||||
Here are the names and descriptions for each tool:
|
||||
${systemPrompt}
|
||||
|
||||
When a tool is required, use the tools provided below.
|
||||
The tools available to you are listed below, along with their names, parameters, and descriptions:
|
||||
IMPORTANT: Never call a tool with a missing required param, without asking them first to the user!
|
||||
List of tools:
|
||||
${toolsAsText}
|
||||
|
||||
${toolsAsText}
|
||||
|
||||
Do not use any previous tools output in the {chat_history}.
|
||||
`
|
||||
),
|
||||
new MessagesPlaceholder('chat_history'),
|
||||
AIMessagePromptTemplate.fromTemplate(`Follow Up Input: {question}
|
||||
new MessagesPlaceholder('chat_history'),
|
||||
HumanMessagePromptTemplate.fromTemplate(`Follow Up Input: {question}
|
||||
Standalone question:`)
|
||||
]);
|
||||
|
||||
|
@ -353,14 +368,23 @@ export class ChatServices {
|
|||
]);
|
||||
|
||||
const toolsResultPrompt = ChatPromptTemplate.fromMessages([
|
||||
AIMessagePromptTemplate.fromTemplate(
|
||||
`The tool just returned value in last call. Using {chat_history}
|
||||
rephrase the answer to the user using this tool output.
|
||||
SystemMessagePromptTemplate.fromTemplate(
|
||||
`
|
||||
${systemPrompt}
|
||||
|
||||
List of tools:
|
||||
${toolsAsText}
|
||||
|
||||
`
|
||||
),
|
||||
new MessagesPlaceholder('chat_history'),
|
||||
AIMessagePromptTemplate.fromTemplate(`Tool output: {tool_output}
|
||||
Standalone question:`)
|
||||
AIMessagePromptTemplate.fromTemplate(
|
||||
`
|
||||
The tool just returned value in last call answer the question based on tool description.
|
||||
`
|
||||
),
|
||||
|
||||
HumanMessagePromptTemplate.fromTemplate(`Tool output: {tool_output}
|
||||
Folowing answer:`)
|
||||
]);
|
||||
|
||||
const jsonInformation = `VERY IMPORTANT: ALWAYS return VALID standard JSON with the folowing structure: 'text' as answer,
|
||||
|
@ -415,13 +439,14 @@ export class ChatServices {
|
|||
tool_output: async (output: object) => {
|
||||
const name = output['func'][0].function.name;
|
||||
const args = JSON.parse(output['func'][0].function.arguments);
|
||||
GBLogEx.info(min, `Running .gbdialog '${name}' as LLM tool...`);
|
||||
GBLogEx.info(min, `LLM Tool called .gbdialog '${name}'...`);
|
||||
const pid = GBVMService.createProcessInfo(null, min, 'LLM', null);
|
||||
|
||||
return await GBVMService.callVM(name, min, false, pid, false, args);
|
||||
},
|
||||
chat_history: async () => {
|
||||
const { chat_history } = await memory.loadMemoryVariables({});
|
||||
|
||||
return chat_history;
|
||||
}
|
||||
},
|
||||
|
@ -623,10 +648,10 @@ export class ChatServices {
|
|||
return Object.keys(tools)
|
||||
.map(toolname => {
|
||||
const tool = tools[toolname];
|
||||
const properties = tool.lc_kwargs.parameters.properties;
|
||||
const properties = tool.lc_kwargs.schema.properties;
|
||||
const params = Object.keys(properties).map(param => {
|
||||
const { description, type } = properties[param];
|
||||
return `${param} (${type}): ${description}`;
|
||||
return `${param} *REQUIRED* (${type}): ${description}`;
|
||||
}).join(', ');
|
||||
|
||||
return `- ${tool.name}: ${tool.description}\n Parameters: ${params?? 'No parameters'}`;
|
||||
|
@ -649,7 +674,7 @@ export class ChatServices {
|
|||
if (funcObj) {
|
||||
// TODO: Use ajv.
|
||||
|
||||
funcObj.schema = jsonSchemaToZod(funcObj.parameters);
|
||||
funcObj.schema = eval(funcObj.schema);
|
||||
functions.push(new DynamicStructuredTool(funcObj));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
name,price
|
||||
fax, 500
|
||||
TV, 1200
|
||||
tv, 1200
|
||||
mobile,200
|
||||
console, 250
|
||||
chocolate, 30
|
||||
|
|
|
|
@ -1,6 +1,9 @@
|
|||
PARAM product AS string LIKE telephone DESCRIPTION The name of the product to have the price retrieved.
|
||||
DESCRIPTION Returns the price of the given product.
|
||||
PARAM product AS string LIKE fax DESCRIPTION "Required name of the item you want to inquire about."
|
||||
DESCRIPTION "Returns the price of the specified product name."
|
||||
|
||||
product = FIND "products.csv", "name = ${product}"
|
||||
price = product.price
|
||||
RETURN price
|
||||
price = -1
|
||||
productRecord = FIND "products.csv", "name = ${product}"
|
||||
IF (productRecord) THEN
|
||||
price = productRecord.price
|
||||
END IF
|
||||
RETURN price
|
||||
|
|
|
@ -4,5 +4,6 @@ There exist some helpful predefined internal tools which can help me by
|
|||
extending my functionalities or get me helpful information.
|
||||
These tools **should** be abstracted away from the user.
|
||||
These tools can be invoked only by me before I respond to a user.
|
||||
If get price tool return value of -1, says there is no such product.
|
||||
|
||||
END SYSTEM PROMPT
|
|
@ -1,2 +1,3 @@
|
|||
name,value
|
||||
Answer Mode,tool
|
||||
Start Dialog,start
|
|
Loading…
Add table
Reference in a new issue