Skip to content

Commit f379e65

Browse files
committed
SimpleChatTC:Propogate toolcall id through tool call chain
Use HTMLElement's dataset to maintain tool call id along with the element which maintains the toolname. Pass it along to the tools manager and inturn the actual tool calls and through them to the web worker handling the tool call related code and inturn returning it back as part of the obj which is used to return the tool call result. Embed the tool call id, function name and function result into the content field of chat message in terms of a xml structure Also make use of tool role to send back the tool call result. Do note that currently the id, name and content are all embedded into the content field of the tool role message sent to the ai engine on the server. NOTE: Use the user query entry area for showing tool call result in the above mentioned xml form, as well as for user to enter their own queries. Based on presence of the xml format data at beginning the logic will treat it has a tool result and if not then as a normal user query. The css has been updated to help show tool results/msgs in a lightyellow background
1 parent 69cbc81 commit f379e65

File tree

5 files changed

+53
-17
lines changed

5 files changed

+53
-17
lines changed

tools/server/public_simplechat/simplechat.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
.role-user {
2222
background-color: lightgray;
2323
}
24+
.role-tool {
25+
background-color: lightyellow;
26+
}
2427
.role-trim {
2528
background-color: lightpink;
2629
}

tools/server/public_simplechat/simplechat.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ class ChatMessageEx {
7777
this.trimmedContent = "";
7878
}
7979

80+
/**
81+
* Create a all in one tool call result string
82+
* @param {string} toolCallId
83+
* @param {string} toolName
84+
* @param {string} toolResult
85+
*/
86+
static createToolCallResultAllInOne(toolCallId, toolName, toolResult) {
87+
return `<tool_response> <id>${toolCallId}</id> <name>${toolName}</name> <content>${toolResult}</content> </tool_response>`;
88+
}
89+
90+
8091
/**
8192
* Update based on the drip by drip data got from network in streaming mode.
8293
* Tries to support both Chat and Completion endpoints
@@ -561,15 +572,16 @@ class SimpleChat {
561572
* Call the requested tool/function.
562573
* Returns undefined, if the call was placed successfully
563574
* Else some appropriate error message will be returned.
575+
* @param {string} toolcallid
564576
* @param {string} toolname
565577
* @param {string} toolargs
566578
*/
567-
async handle_toolcall(toolname, toolargs) {
579+
async handle_toolcall(toolcallid, toolname, toolargs) {
568580
if (toolname === "") {
569581
return "Tool/Function call name not specified"
570582
}
571583
try {
572-
return await tools.tool_call(toolname, toolargs)
584+
return await tools.tool_call(toolcallid, toolname, toolargs)
573585
} catch (/** @type {any} */error) {
574586
return `Tool/Function call raised an exception:${error.name}:${error.message}`
575587
}
@@ -633,11 +645,13 @@ class MultiChatUI {
633645
if (ar.has_toolcall()) {
634646
this.elDivTool.hidden = false
635647
this.elInToolName.value = ar.ns.tool_calls[0].function.name
648+
this.elInToolName.dataset.tool_call_id = ar.ns.tool_calls[0].id
636649
this.elInToolArgs.value = ar.ns.tool_calls[0].function.arguments
637650
this.elBtnTool.disabled = false
638651
} else {
639652
this.elDivTool.hidden = true
640653
this.elInToolName.value = ""
654+
this.elInToolName.dataset.tool_call_id = ""
641655
this.elInToolArgs.value = ""
642656
this.elBtnTool.disabled = true
643657
}
@@ -697,9 +711,9 @@ class MultiChatUI {
697711
this.handle_tool_run(this.curChatId);
698712
})
699713

700-
tools.setup((name, data)=>{
714+
tools.setup((id, name, data)=>{
701715
clearTimeout(this.idTimeOut)
702-
this.elInUser.value = `<tool_response>${data}</tool_response>`
716+
this.elInUser.value = ChatMessageEx.createToolCallResultAllInOne(id, name, data);
703717
this.ui_reset_userinput(false)
704718
})
705719

@@ -744,6 +758,14 @@ class MultiChatUI {
744758

745759
/**
746760
* Handle user query submit request, wrt specified chat session.
761+
* NOTE: Currently the user query entry area is used for
762+
* * showing and allowing edits by user wrt tool call results
763+
* in a predfined simple xml format,
764+
* ie before they submit tool result to ai engine on server
765+
* * as well as for user to enter their own queries.
766+
* Based on presence of the predefined xml format data at beginning
767+
* the logic will treat it has a tool result and if not then as a
768+
* normal user query.
747769
* @param {string} chatId
748770
* @param {string} apiEP
749771
*/
@@ -768,7 +790,11 @@ class MultiChatUI {
768790
console.debug(`WARN:SimpleChat:MCUI:${chatId}:HandleUserSubmit:Ignoring empty user input...`);
769791
return;
770792
}
771-
chat.add(new ChatMessageEx(Roles.User, content))
793+
if (content.startsWith("<tool_response>")) {
794+
chat.add(new ChatMessageEx(Roles.Tool, content))
795+
} else {
796+
chat.add(new ChatMessageEx(Roles.User, content))
797+
}
772798
chat.show(this.elDivChat);
773799

774800
let theUrl = ApiEP.Url(gMe.baseURL, apiEP);
@@ -808,13 +834,17 @@ class MultiChatUI {
808834
this.elInUser.value = "toolcall in progress...";
809835
this.elInUser.disabled = true;
810836
let toolname = this.elInToolName.value.trim()
811-
let toolResult = await chat.handle_toolcall(toolname, this.elInToolArgs.value)
837+
let toolCallId = this.elInToolName.dataset.tool_call_id;
838+
if (toolCallId === undefined) {
839+
toolCallId = "??? ToolCallId Missing ???"
840+
}
841+
let toolResult = await chat.handle_toolcall(toolCallId, toolname, this.elInToolArgs.value)
812842
if (toolResult !== undefined) {
813-
this.elInUser.value = `<tool_response>${toolResult}</tool_response>`
843+
this.elInUser.value = ChatMessageEx.createToolCallResultAllInOne(toolCallId, toolname, toolResult);
814844
this.ui_reset_userinput(false)
815845
} else {
816846
this.idTimeOut = setTimeout(() => {
817-
this.elInUser.value = `<tool_response>Tool/Function call ${toolname} taking too much time, aborting...</tool_response>`
847+
this.elInUser.value = ChatMessageEx.createToolCallResultAllInOne(toolCallId, toolname, `Tool/Function call ${toolname} taking too much time, aborting...`);
818848
this.ui_reset_userinput(false)
819849
}, 10000)
820850
}

tools/server/public_simplechat/tooljs.mjs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ let js_meta = {
3232
/**
3333
* Implementation of the javascript interpretor logic. Minimal skeleton for now.
3434
* ALERT: Has access to the javascript web worker environment and can mess with it and beyond
35+
* @param {string} toolcallid
3536
* @param {string} toolname
3637
* @param {any} obj
3738
*/
38-
function js_run(toolname, obj) {
39-
gToolsWorker.postMessage({ name: toolname, code: obj["code"]})
39+
function js_run(toolcallid, toolname, obj) {
40+
gToolsWorker.postMessage({ id: toolcallid, name: toolname, code: obj["code"]})
4041
}
4142

4243

@@ -62,11 +63,12 @@ let calc_meta = {
6263
/**
6364
* Implementation of the simple calculator logic. Minimal skeleton for now.
6465
* ALERT: Has access to the javascript web worker environment and can mess with it and beyond
66+
* @param {string} toolcallid
6567
* @param {string} toolname
6668
* @param {any} obj
6769
*/
68-
function calc_run(toolname, obj) {
69-
gToolsWorker.postMessage({ name: toolname, code: `console.log(${obj["arithexpr"]})`})
70+
function calc_run(toolcallid, toolname, obj) {
71+
gToolsWorker.postMessage({ id: toolcallid, name: toolname, code: `console.log(${obj["arithexpr"]})`})
7072
}
7173

7274

tools/server/public_simplechat/tools.mjs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ export function meta() {
3232
/**
3333
* Setup the callback that will be called when ever message
3434
* is recieved from the Tools Web Worker.
35-
* @param {(name: string, data: string) => void} cb
35+
* @param {(id: string, name: string, data: string) => void} cb
3636
*/
3737
export function setup(cb) {
3838
gToolsWorker.onmessage = function (ev) {
39-
cb(ev.data.name, ev.data.data)
39+
cb(ev.data.id, ev.data.name, ev.data.data)
4040
}
4141
}
4242

@@ -45,14 +45,15 @@ export function setup(cb) {
4545
* Try call the specified tool/function call.
4646
* Returns undefined, if the call was placed successfully
4747
* Else some appropriate error message will be returned.
48+
* @param {string} toolcallid
4849
* @param {string} toolname
4950
* @param {string} toolargs
5051
*/
51-
export async function tool_call(toolname, toolargs) {
52+
export async function tool_call(toolcallid, toolname, toolargs) {
5253
for (const fn in tc_switch) {
5354
if (fn == toolname) {
5455
try {
55-
tc_switch[fn]["handler"](fn, JSON.parse(toolargs))
56+
tc_switch[fn]["handler"](toolcallid, fn, JSON.parse(toolargs))
5657
return undefined
5758
} catch (/** @type {any} */error) {
5859
return `Tool/Function call raised an exception:${error.name}:${error.message}`

tools/server/public_simplechat/toolsworker.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ self.onmessage = function (ev) {
2121
console.log(`\n\nTool/Function call "${ev.data.name}" raised an exception:${error.name}:${error.message}\n\n`)
2222
}
2323
tconsole.console_revert()
24-
self.postMessage({ name: ev.data.name, data: tconsole.gConsoleStr})
24+
self.postMessage({ id: ev.data.id, name: ev.data.name, data: tconsole.gConsoleStr})
2525
}

0 commit comments

Comments
 (0)