As I was seeing the truncated message even for stripped plain text
web acces, relooking at that initial go at truncating, revealed
a oversight, which had the truncation logic trigger anytime the
iResultMaxDataLength was greater than 0, irrespective of whether
the actual result was smaller than the allowed limit or not,
thus adding that truncated message to end of result unnecessarily.
Have fixed that oversight
Also recent any number of args based simpleprox handshake helper
in toolweb seems to be working (atleast for the existing single
arg based calls).
This makes the logic more generic, as well as prepares for additional
parameters to be passed to the simpleproxy.py helper handshakes.
Ex: Restrict extracted contents of a pdf to specified start and end
page numbers or so.
Needed to tweak the description further for the ai model to be
able to understand that its ok to pass file:// scheme based urls
Had forgotten how big the web site pages have become as also the
need for more ResultDataLength wrt one shot PDF read to get
atleast some good enough amount of content in it with large pdfs
Allow user to limit the max amount of result data returned to ai
after a tool call.
Inturn it is set by default to 2K.
Update the pdf2text tool description to try make the local file
path support more explicit
Make the description bit more explicit with it supporting local
file paths as part of the url scheme, as the tested ai model was
cribbing about not supporting file url scheme. Need to check if
this new description will make things better.
Convert the text to bytes for writing to the http pipe.
Ensure CORS is kept happy by passing AccessControlAllowOrigin in
header.
move the actual chat handshake with ai server into a seperate code
to an extent.
also initial anchor to trap handshake http error responses
Rather come to think of it, its better to move this into SimpleChat
class.
Use finally to ensure any needed cleanup for handle_user_submit
occurs within itself.
Update the descriptions of set and get to indicate the possible
corner cases or rather semantic in such situations.
Update the readme also a bit. The auto save and restore mentioned
has nothing to do with the new data store mechanism.
In the eagerness of initial skeleton, had forgotten that the
root/generic tool call router takes care of parsing the json string
into a object, before calling the tool call, so no need to try
parse again. Fixed the same.
Hadnt converted the object based response from data store related
calls in the db web worker, into json string before passing to the
generic tool response callback, fixed the same.
- Rather the though of making the ChatMsgEx.createAllInOne handle
string or object set aside for now, to keep things simple and
consistant to the greatest extent possible across different flows.
And good news - flow is working atleast for the overall happy path
Need to check what corner cases are lurking like calling set on
same key more than once, seemed to have some flow oddity, which I
need to check later.
Also maybe change the field name to value from data in the response
to get, to match the field name convention of set. GPT-OSS is fine
with it. But worst case micro / nano / pico models may trip up, in
worst case, so better to keep things consistent.
So mention that may be ai can send complex objects in stringified
form. Rather once type of value is set to string, ai should normally
do it, but no harm is hinting.
Create the DB store
Try Get and Set operations
The post back to main thread done from asynchronous paths.
NOTE: given that it has been ages since indexed db was used,
so this is a logical implementation by refering to mdn as needed.
Define rules to ensure that chat message contents wrap so as to
avoid overflowing beyond the size of the screen being viewed.
The style used for chat message role to be placed with vertical
oriented text adjacent to the actual message content on the side
seems to be creating issue with blank pages in some browsers,
so avoid that styling when one is printing.
Seperate out the message ui block into a container containing
a role block and contents container block.
This will allow themeing of these seperately, if required.
As part of same, currently the role has been put to the side
of the message with vertical text flow.
Add a newline between name and content in the xml representation
of the tool response, so that it is more easy to distinguish things
Add github, linkedin and apnews domains to allowed.domains for
simpleproxy.py
Fix up the initial skeleton / logic as needed.
Remember that we are working with potentially a subset of chat
messages from the session, given the sliding window logic of
context managing on client ui side, so fix up the logic to use
the right subset of messages array and not the global xchat
when deciding whether a message is the last or last but one,
which need special handling wrt Assistant (with toolcall) and
Tool (ie response) messages.
Moving tool call ui setup as well as tool call response got ui
setup into ChatShow of MultiChatUI ensures that switching between
chat sessions handle the ui wrt tool call triggering ui and tool
call response submission related ui as needed properly.
Rather even loading a previously auto saved chat session if it had
tool call or tool call response to be handled, the chat ui will be
setup as needed to continue that session properly.
Rather simplify and make the content_equiv provide a relatively
simple and neat representation of the reasoning with content and
toolcall as the cases may be.
Also remove the partial new para that I had introduced in the
initial go for reasoning.
Pass chatId to tool call, and use chatId in got tool call resp,
to decide as to to which chat session the async tool call resp
belongs and inturn if auto submit timer should be started if auto
is enabled.
Update the immidiate tool call triggering failure and tool call
response timeout paths to use the new ToolTemp and MultiChatUI
based chat show logics.
Actual tool call itself generating errors, is already handled
in the previous commit changes.
Add a new role ToolTemp, which is used to maintain any tool call
response on the client ui side, without submitting it to the server
ie till user or auto submit triggers the submitting of that tool
call response.
When ever a tool call response is got, create a ToolTemp role based
message in the corresponding chat session. And dont directly update
the user query input area, rather leave it to the updated simplechat
show and the new multichatui chat_show helper and inturn whether the
current chat session active in ui is same as the one for which the
tool call response has been recieved.
TODO: Currently the response message is added to the current
active chat session, but this needs to be changed by tracking
chatId/session through the full tool call cycle and then adding
the tool call response in the related chat session, and inturn
updating or not the ui based on whether that chat session is
still the active chat session in ui or not, given that tool call
gets handled in a asynchronous way.
Now when that tool call response is submitted, promote the equiv
tool temp role based message that should be in the session's chat
history as the last message into becoming a normal tool response
message.
SimpleChat.show has been updated to take care of showing any
ToolTemp role message in the user query input area.
A newer chat_show helper added to MultiChatUI, that takes care of
calling SimpleChat.show, provided the chat_show is being requested
for the currently active in ui, chat session. As well as to take
care of passing both the ChatDiv and elInUser. Converts users of
SimpleChat.show to use MultiChatUI.chat_show
instead of using the shared bearer token as is, hash it with
current year and use the hash.
keep /aum path out of auth check.
in future bearer token could be transformed more often, as well as
with additional nounce/dynamic token from server got during initial
/aum handshake as also running counter and so ...
NOTE: All these circus not good enough, given that currently the
simpleproxy.py handshakes work over http. However these skeletons
put in place, for future, if needed.
TODO: There is a once in a bluemoon race when the year transitions
between client generating the request and server handling the req.
But other wise year transitions dont matter bcas client always
creates fresh token, and server checks for year change to genrate
fresh token if required.
Add a config entry called bearer.insecure which will contain a
token used for bearer auth of http requests
Make bearer.insecure and allowed.domains as needed configs, and
exit program if they arent got through cmdline or config file.
Ensure load_config gets called on encountering --config in cmdline,
so that the user has control over whether cmdline or config file
will decide the final value of any given parameter.
Ensure that str type values in cmdline are picked up directly, without
running them through ast.literal_eval, bcas otherwise one will have to
ensure throught the cmdline arg mechanism that string quote is retained
for literal_eval
Have the """ function note/description below def line immidiately
so that it is interpreted as a function description.
Now both follow a similar mechanism and do the following
* exit on finding any issue, so that things are in a known
state from usage perspective, without any confusion/overlook
* check if the cmdlineArgCmd/configCmd being processed is a known
one or not.
* check value of the cmd is of the expected type
* have a generic flow which can accomodate more cmds in future
in a simple way
Moved it into Me->tools, so that end user can modify the same as
required from the settings ui.
TODO: Currently, if tc response is got after a tool call timed out
and user submitted default timed out error response, the delayed
actual response when it is got may overwrite any new content in
user query box, this needs to be tackled.
Avoid code duplication, by creating helpers for setup and toolcall.
Also send indication of the path that will be used, when checking
for simpleproxy.py server to be running at runtime setup.
Initial go at implementing a web search tool call, which uses the
existing UrlText support of the bundled simpleproxy.py.
It allows user to control the search engine to use, by allowing
them to set the search engine url template.
The logic comes with search engine url template strings for
duckduckgo, brave, bing and google. With duckduckgo set by default.
include info about the auto option within tools.
use nonwrapped text wrt certain sections, so that the markdown
readme can be viewed properly wrt the structure of the content
in it.
Instead of enforcing always explicit user triggered tool calling,
now user is given the option whether to use explicit user triggered
tool calling or to use auto triggering after showing tool details
for a user specified amount of seconds.
NOTE: The current logic doesnt account for user clicking the buttons
before the autoclick triggers; need to cancel the auto clicks, if
user triggers before autoclick, ie in future.
bing raised a challenge for chrome triggered search requests after
few requests, which were spread few minutes apart, while still
seemingly allowing wget based search to continue (again spread
few minutes apart).
Added a simple helper to trace this, use --debug True to enable
same.
Instead of simple concatenating of tool call id, name and result
now use browser's dom logic to create the xml structure used for
now to store these within content field.
This should take care of transforming / escaping any xml special
chars in the result, so that extracting them later for putting
into different fields in the server handshake doesnt have any
problem.
Use DOMParser parseFromString in text/html mode rather than text/xml
as it makes it more relaxed without worrying about special chars
of xml like & etal
mimicing got req in generated req helps with duckduckgo also and
not just yahoo.
also update allowed.domains to allow a url generated by ai when
trying to access the bing's news aggregation url
The tagging of messages wrt ValidateUrl and UrlReq
Also dump req
Move check for --allowed.domains to ValidateUrl
NOTE: Also with mimicing of user agent etal from got request to
the generated request, yahoo search/news is returning results now,
instead of the bland error before.
with allowed domains set to few sites in general to show its use
this includes some sites which allow search to be carried out
through them as well as provide news aggregation
Had confused between js and python wrt accessing dictionary
contents and its consequence on non existent key. Fixed it.
Use different error ids to distinguish between failure in common
urlreq and the specific urltext and urlraw helpers.
Also remove more inner/detailed stuff from show info in not bAll
mode, given that many of the previous differentiated stuff have
been moved into chatProps and inturn shown for now
Fix up the oversights wrt any depth trapping flow
Remember to start the propWithTree being checked/trapped with :
to indicate the root of the prop hierarchy and also use : as sep
between the elements of the props hierarchy tree
Also had forgotten about the goof up possible with using in in a
condition statement to check for array to contain a entry of interest
in JS, fixed it now.
Maintain the current property hierarchy to its root over recursive
calls.
Allow callers to specify the props to be trapped using the prop
hierarchy.
Pass the prop hierarchy to the fTrapper.
This should allow one to trap any prop wrt its editing ui setup,
irrespective of whether it is a prop of the main object passed,
or a member of a child prop of the main object passed or so ...
Update the setting up of ChatHistoryInCtxt and ApiEndPoint to follow
the new semantic/flow.
NOTE: not a robust check, just tries to establish a http connection
for now and doesnt really check if it is the specific proxy srvr
of interest or not.
Take care of the possibility of content not being there as well as
take care of retrieving the tool calls for further processing.
With this tool calls should work in non streaming mode also
Make the previously relatively generic flow wrt apiRequestOptions
settings into a fully generic reusable by others flow.
Rather had stopped short of it, when previously moved onto other
things at that time.
So that the same error path is used for logical error wrt http req
also, without needing a different path for it.
Dont forget to return the resp text/json/..., so that the contents
are passed along the promise then chain
Add a new send headers common helper and use the same wrt the
overridden send_error as well as do_OPTIONS
This ensures that if there is any error during proxy opertions,
the send_error propogates to the fetch from any browser properly
without browser intercepting it with a CORS error
Ensures that if the url being requested as any query strings in
them then things dont get messed up, when the url to get inc its
query is extracted from the proxy request's query string
First identify lines which have only whitespace and replace them
with lines with only newline char in them.
Next strip out adjacent lines, if they have only newlines
As html can be malformed, xml ElementTree XMLParser cant handle
the same properly, so switch to the HtmlParser helper class that is
provided by python and try extend it.
Currently a minimal skeleton to just start it out, which captures
only the body contents.
Declare the result of UrlReq as a DataClass, so that one doesnt
goof up wrt updating and accessing members.
Duplicate UrlRaw into UrlText, need to add Text extracting from
html next for UrlText
Dont forget to map members of got entity from fetch to things
from saved original promise, bcas remember what is got is a promise.
also
add some comments around certain decisions and needed exploration
also possible refinement wrt trapping, if needed, added as comment
all or allSettled to use or not is the question.
whether to wait for a round trip through the related event loop or
not is also a question.
Also update the sliding window context size to last 9 chat messages
so that there is a sufficiently large context for multi turn tool
calls based adjusting by ai and user, without needing to go full
hog, which has the issue of overflowing the currently set context
window wrt the loaded ai model.
these common helpers avoid needing ignore tagging to ts-check, in
places where valid constructs have been used which go beyond strict
structured js handling that is tried to be achieved using it, but
are still valid and legal.
Expand the xml format id, name and content in content field of
tool result into apropriate fields in the tool result message sent
to the genai/llm engine on the server.
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
Users of recent_chat updated to work with ChatMessageEx
As part of same recent_chat_ns also added, for the case where the
array of chat messages can be passed as is ie in the chat mode,
provided it has only the network handshake representation of the
messages.
Simplify Add semantic by expecting any validation of stuff before
adding to be done by the callers of Add and not by add itself.
Also update it to expect ChatMessageEx object
Update all users of add to follow the new syntax and semantic.
Remove the old and ununsed AddSysPromptOnlyAtBegin helper
GetSystemLatest and its users updated wrt ChatMessageEx.
RecentChat updated wrt ChatMessageEx. Also now irrespective of
whether full history is being retrieved or only a subset, both
cases refer to the ChatMessageEx instances in SimpleChat.xchat
without creating new instances of anything.
Use the equivalent update_stream directly added to ChatMessageEx.
update_stream is also more generic to some extent and also directly
implemented by the ChatMessageEx class.
Rename ChatMessage to ChatMessageEx.
Add typedefs for NSToolCall and NSChatMessage, they represent the
way the corresponding data is structured in network hs.
Add logic to build the ChatMessageEx from data got over network in
streaming mode.
As the tool calling, if enabled, will need access to last few
user query and ai assistant responses (which will also include
in them the tool call requests and the corresponding results),
so that the model can build answers based on its tool call reqs
and got responses, and also given that most of the models these
days have sufficiently large context windows, so the sliding
window context implemented by SimpleChat logic has been increased
by default to include last 4 query and their responses roughlty.
Had forgotten to specify type as module wrt web worker, in order
to allow it to import the toolsconsole module.
Had forgotten to maintain the id of the timeout handler, which is
needed to clear/stop the timeout handler from triggering, if tool
call response is got well in time.
As I am currently reverting the console redirection at end of
handling a tool call code in the web worker message handler, I
need to setup the redirection each time. Also I had forgotten
to clear the console.log capture data space, before a new tool
call code is executed, this is also fixed by this change.
TODO: Need to abort the tool call code execution in the web worker
if possible in future, if the client / browser side times out
waiting for tool call response, ie if the tool call code is taking
up too much time.
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.
These no longer need to worry about
* setting up the console.log related redirection to capture
the generated outputs, nor about
* setting up a dynamic function for executing the needed
tool call related code
The web worker setup to help run tool calls in a relatively
isolated environment independent of the main browser env,
takes care of these.
One needs to only worry about getting the handle to the
web worker to use and inturn pass the need code wrt the
tool call to it.
The request for code to run as well as the resultant response data
both need to follow a structured object convention, so that it is
easy to map a request and the corresponding response to some extent.
Try ensure as well as verify that original console.log is saved
and not overwritten. Throw an exception if things seem off wrt
same.
Also ensure to add a newline at end of console.log messages
Instead of automatically calling any requested tool by the GenAi
/ llm, that is from the tail end of the handle user submit btn
click,
Now if the GenAi/LLM has requested any tool to be called, then
enable the Tool Run related UI elements and fill them with the
tool name and tool args.
In turn the user can verify if they are ok with the tool being
called and the arguments being passed to it. Rather they can
even fix any errors in the tool usage like the arithmatic expr
to calculate that is being passed to simple_calculator or the
javascript code being passed to run_javascript_function_code
If user is ok with the tool call being requested, then trigger
the same.
The results if any will be automatically placed into the user
query text area.
User can cross verify if they are ok with the result and or
modify it suitabley if required and inturn submit the same to
the GenAi/LLM.
Instead of automatically calling the requested tool with supplied
arguments, rather allow user to verify things before triggering the
tool.
NOTE: User already provided control over tool_response before
submitting it to the ai assistant.
So that when tool handler writes the result to the tc_switch, it
can make use of the same, to write to the right location.
NOTE: This also fixes the issue with I forgetting to rename the
key in js_run wrt writing of result.
Move tool calling logic into tools module.
Try trap async promise failures by awaiting results of tool calling
and putting full thing in an outer try catch. Have forgotten the
nitty gritties of JS flow, this might help, need to check.
As output generated by any tool/function call is currently placed
into the TextArea provided for End user (for their queries), bcas
the GenAi (engine/LLM) may be expecting the tool response to be
sent as a user role data with tool_response tag surrounding the
results from the tool call. So also now at the end of submit btn
click handling, the end user input text area is not cleared, if
there was a tool call handled, for above reasons.
Also given that running a simple arithmatic expression in itself
doesnt generate any output, so wrap them in a console.log, to
help capture the result using the console.log trapping flow that
is already setup.
Checks for toolname to be defined or not in the GenAi's response
If toolname is set, then check if a corresponding tool/func exists,
and if so call the same by passing it the GenAi provided toolargs
as a object.
Inturn the text generated by the tool/func is captured and put
into the user input entry text box, with tool_response tag around
it.
The implementations of javascript and simple_calculator now use
provided helpers to trap console.log messages when they execute
the code / expression provided by GenAi and inturn store the
captured log messages in the newly added result key in tc_switch
This should help trap the output generated by the provided code
or expression as the case maybe and inturn return the same to the
GenAi, for its further processing.
Previously if content was empty, it would have always sent the
toolcall info related version even if there was no toolcall info
in it. Fixed now to return empty string, if both content and
toolname are empty.
As there could be failure wrt getting the response from the ai
server some where in between a long response spread over multiple
parts, the logic uses the latestResponse to cache the response
as it is being received. However once the full response is got,
one needs to transfer it to a new instance of AssistantResponse
class, so that latestResponse can be cleared, while the new
instance can be used in other locations in the flow as needed.
Achieve the same now.
Switch oneshot handler to use AssistantResponse, inturn currenlty
only handle the normal content in the response.
TODO: If any tool_calls in the oneshot response, it is currently
not handled.
Inturn switch the generic/toplevel handle response logic to use
AssistantResponse class, given that both oneshot and the
multipart/streaming flows use/return it.
Inturn add trimmedContent member to AssistantResponse class and
make the generic handle response logic to save the trimmed content
into this. Update users of trimmed to work with this structure.
Make latestResponse into a new class based type instance wrt
ai assistant response, which is what it represents.
Move clearing, appending fields' values and getting assistant's
response info (irrespective of a content or toolcall response)
into this new class and inturn use the same.
I was wrongly checking for finish_reason to be non null, before
trying to extract the genai content/toolcalls, have fixed this
oversight with the new flow in progress.
I had added few debug logs to identify the above issue, need to
remove them later. Note: given that debug logs are disabled by
replacing the debug function during this program's initialisation,
which I had forgotten about, I didnt get the debug messages and
had to scratch my head a bit, before realising this and the other
issue ;)
Also either when I had originally implemented simplechat 1+ years
back, or later due to changes on the server end, the streaming
flow sends a initial null wrt the content, where it only sets the
role. This was not handled in my flow on the client side, so a
null was getting prepended to the chat messages/responses from the
server. This has been fixed now in the new generic flow.
Update response_extract_stream to check for which field is being
currently streamed ie is it normal content or tool call func name
or tool call func args and then return the field name and extracted
value.
Previously it was always assumed that only normal content will be
returned.
Currently it is assumed that the server will only stream one of the
3 supported fields at any time and not more than one of them at the
same time.
TODO: Have to also add logic to extract the reasoning field later,
ie wrt gen ai models which give out their thinking.
Have updated append_response to expect both the key and the value
wrt the latestResponse object, which it will be manipualted.
Previously it was always assumed that content is what will be got
and inturn appended.
Changed latestResponse type to an object instead of a string.
Inturn it contains entries for content, toolname and toolargs.
Added a custom clear logic due to the same and used it to replace
the previously simple assigning of empty string to latestResponse.
For now in all places where latestReponse is used, I have replaced
with latestReponse.content.
Next need to handle identifying the field being streamed and inturn
append to it. Also need to add logic to call tool, when tool_call
triggered by genai.