module api export prompt using JSON, DataStructures, Dates, UUIDs, HTTP, Random, PrettyPrinting, Serialization, DataFrames using GeneralUtils using ..type, ..utils, ..agentCore, ..toolRegistry # ---------------------------------------------- 100 --------------------------------------------- # """ Send a message to the agent's input channel. Blocks if the input channel buffer is full (capacity 16 by default). The agent processes messages from `inputChannel` in the background task. # Arguments - `agent::yiemAgent`: The agent instance to send a message to - `msg`: The message to send (any type accepted by the agent's processing pipeline) # Returns - The same `agent` instance for chaining # Notes - Use `takeResponse(agent)` to receive the agent's response after sending a message. - Use `followUp(agent, msg)` to send messages while the agent is still processing. # Examples ```jldoctest julia> runAgent(agent, "Hello!") yiemAgent(...) ``` """ function runAgent(agent::yiemAgent, msg) put!(agent.inputChannel, msg) return agent end """ Take a response from the agent's output channel. Blocks until the agent sends a response. # Arguments - `agent::yiemAgent`: The agent instance to receive a response from # Returns - An `assistantMessage` instance representing the agent's response # Notes - Use `runAgent(agent, msg)` to send a message before calling this function. # Examples ```jldoctest julia> response = takeResponse(agent) assistantMessage(...) ``` """ function takeResponse(agent::yiemAgent) return take!(agent.outputChannel) end """ Send a follow-up message while the agent is still processing. Follow-up messages are queued and processed after all `inputChannel` messages and before any tool call results are sent. # Arguments - `agent::yiemAgent`: The agent instance to send a follow-up message to - `msg`: The follow-up message to send # Returns - The same `agent` instance for chaining # Notes - Use `runAgent(agent, msg)` for the primary message and `followUp(agent, msg)` for additional messages while the agent is processing. - Follow-up messages are buffered in a separate channel (capacity 32 by default). # Examples ```jldoctest julia> followUp(agent, "Also consider red wines") yiemAgent(...) ``` """ function followUp(agent::yiemAgent, msg) put!(agent.followUpChannel, msg) return agent end """ Gracefully stop the agent. Sends a `:shutdown` signal to the input channel, waits for the background task to finish, then closes all channels (`inputChannel`, `outputChannel`, `followUpChannel`). # Arguments - `agent::yiemAgent`: The agent instance to stop # Returns - `nothing` # Notes - After calling `stopAgent`, the agent is no longer usable. A new agent must be created for further interaction. - If the background task throws a `TaskFailedException`, it is rethrown. # Examples ```jldoctest julia> stopAgent(agent) ``` """ function stopAgent(agent::yiemAgent) put!(agent.inputChannel, :shutdown) try fetch(agent._agent_loop) catch e if e isa TaskFailedException rethrow(e) end end close(agent.inputChannel) close(agent.outputChannel) close(agent.followUpChannel) return nothing end """ Recursively convert dictionary-like variable (e.g. JSON.Object) into an OrderedDict. The function walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`, `Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where every dictionary-like node is an `OrderedDict` and every array-like node is a `Vector{Any}`. Scalar values (numbers, strings, booleans, `nothing`, etc.) are returned unchanged. Does **not** mutate the input; it always allocates new containers. # Arguments - `x` Any Julia value. If `x` is an `AbstractDict` it will be converted to an `OrderedDict`; if it is an `AbstractArray` its elements will be processed recursively. # Keyword Arguments - `keytype::Type=Any` The key type for the output OrderedDict. Use `String` for `OrderedDict{String,Any}`, `Symbol` for `OrderedDict{Symbol,Any}`, or `Any` to preserve original key types. - `sort_order::Union{Nothing, Vector}=nothing` Vector of keys specifying the desired order. Keys are arranged in the specified order first, followed by any remaining keys. # Return - A newly allocated nested structure composed of `OrderedDict{keytype,Any}` and `Vector{Any}` that mirrors the input shape but uses ordered Julia containers. # Notes - The function treats any `AbstractDict` as a mapping source, so it works with `JSON.Object`, `Dict`, `OrderedDict`, etc. - Arrays are returned as `Vector{Any}` with their elements processed recursively. # Examples ```jldoctest julia> using JSON, DataStructures julia> d = Dict( "a" => 4, "b" => 6, "c" => Dict( "d"=>7, :e=>Dict( "f"=>"hey", "g"=>Dict( "world"=>[1, "2", 3, Dict(:dd=>4.7)] ) ) ) ) julia> jsonstring = JSON.json(d) julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object julia> A2 = dictify(A1; keytype=String) OrderedDict{String,Any} with 3 entries: "a" => 4 "b" => 6 "c" => OrderedDict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7]))) julia> A3 = dictify(A1; keytype=Symbol) OrderedDict{Symbol,Any} with 3 entries: :a => 4 :b => 6 :c => OrderedDict(:d=>7, :e=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7]))) julia> B1 = dictify(d; keytype=String) OrderedDict{String, Any} with 3 entries: ``` **With sort_order:** ```jldoctest julia> d = Dict("a"=>1, "b"=>2, "c"=>3) julia> dictify(d; sort_order=["c", "a"]) OrderedDict{String,Int} with 3 entries: "c" => 3 "a" => 1 "b" => 2 ``` """ function dictify(x::T; keytype::Type=Any, sort_order::Union{Nothing, Vector}=nothing )::OrderedDict where {T<:AbstractDict} # this function is example end end # module interface