SimpleChatTC: Get ready for decoupled tool call response

tools manager/module

* setup the web worker that will help execute the tool call related
  codes in a js environment that is isolated from the browsers main
  js environment

* pass the web worker to the tool call providers, for them to use

* dont wait for the result from the tool call, as it will be got
  later asynchronously through a message

* allow users of the tools manager to register a call back, which
  will be called when ever a message is got from the web worker
  containing response wrt previously requested tool call execution.

simplechat

* decouple toolcall response handling and toolcall requesting logic

* setup a timeout to take back control if tool call takes up too
  much time. Inturn help alert the ai model, that the tool call
  took up too much time and so was aborted, by placing a approriate
  tagged tool response into user query area.

* register a call back that will be called when response is got
  asynchronously wrt anye requested tool calls.
  In turn take care of updating the user query area with response
  got wrt the tool call, along with tool response tag around it.
This commit is contained in:
hanishkvc 2025-10-14 01:06:00 +05:30
parent 2a8bd1c9e7
commit 148ec1c41a
2 changed files with 37 additions and 8 deletions

View File

@ -539,13 +539,15 @@ class SimpleChat {
}
/**
* Call the requested tool/function and get its response
* Call the requested tool/function.
* Returns undefined, if the call was placed successfully
* Else some appropriate error message will be returned.
* @param {string} toolname
* @param {string} toolargs
*/
async handle_toolcall(toolname, toolargs) {
if (toolname === "") {
return undefined
return "Tool/Function call name not specified"
}
try {
return await tools.tool_call(toolname, toolargs)
@ -675,6 +677,11 @@ class MultiChatUI {
this.handle_tool_run(this.curChatId);
})
tools.setup((name, data)=>{
this.elInUser.value = `<tool_response>${data}</tool_response>`
this.ui_reset_userinput(false)
})
this.elInUser.addEventListener("keyup", (ev)=> {
// allow user to insert enter into their message using shift+enter.
// while just pressing enter key will lead to submitting.
@ -771,17 +778,24 @@ class MultiChatUI {
/**
* Handle running of specified tool call if any, for the specified chat session.
* Also sets up a timeout, so that user gets control back to interact with the ai model.
* @param {string} chatId
*/
async handle_tool_run(chatId) {
let chat = this.simpleChats[chatId];
this.elInUser.value = "toolcall in progress...";
this.elInUser.disabled = true;
let toolResult = await chat.handle_toolcall(this.elInToolName.value, this.elInToolArgs.value)
let toolname = this.elInToolName.value.trim()
let toolResult = await chat.handle_toolcall(toolname, this.elInToolArgs.value)
if (toolResult !== undefined) {
this.elInUser.value = `<tool_response>${toolResult}</tool_response>`
this.ui_reset_userinput(false)
} else {
setTimeout(() => {
this.elInUser.value = `<tool_response>Tool/Function call ${toolname} taking too much time, aborting...</tool_response>`
this.ui_reset_userinput(false)
}, 10000)
}
this.ui_reset_userinput(toolResult === undefined);
}
/**
@ -1073,7 +1087,7 @@ function startme() {
document["gMe"] = gMe;
document["du"] = du;
document["tools"] = tools;
tools.setup()
tools.init()
for (let cid of gMe.defaultChatIds) {
gMe.multiChat.new_chat_session(cid);
}

View File

@ -8,12 +8,14 @@
import * as tjs from './tooljs.mjs'
let gToolsWorker = new Worker('./toolsworker.mjs');
/**
* @type {Object<string,Object<string,any>>}
*/
export let tc_switch = {}
export function setup() {
export function init() {
tjs.init(gToolsWorker)
for (const key in tjs.tc_switch) {
tc_switch[key] = tjs.tc_switch[key]
}
@ -27,9 +29,22 @@ export function meta() {
return tools
}
/**
* Setup the callback that will be called when ever message
* is recieved from the Tools Web Worker.
* @param {(name: string, data: string) => void} cb
*/
export function setup(cb) {
gToolsWorker.onmessage = function (ev) {
cb(ev.data.name, ev.data.data)
}
}
/**
* Try call the specified tool/function call and return its response
* Try call the specified tool/function call.
* Returns undefined, if the call was placed successfully
* Else some appropriate error message will be returned.
* @param {string} toolname
* @param {string} toolargs
*/
@ -38,7 +53,7 @@ export async function tool_call(toolname, toolargs) {
if (fn == toolname) {
try {
tc_switch[fn]["handler"](fn, JSON.parse(toolargs))
return tc_switch[fn]["result"]
return undefined
} catch (/** @type {any} */error) {
return `Tool/Function call raised an exception:${error.name}:${error.message}`
}