Class ::nsmcp::ChatCompletionsBackend (public)
::nx::Class ::nsmcp::ChatCompletionsBackend
Defined in /usr/local/ns/tcl/nsmcp/question-chat-completions.tcl
- Testcases:
- No testcase defined.
Source code: :property apiUrl:required :property apiKeyFile:required :property tokenFile:required :property model:required :property {registry ::nsmcp::tools} :property {authenticator ::nsmcp::auth} :property {authorizer ::nsmcp::authorization} :property {apiOptions {{} object {}}} :property {timeout 180} :property {maxResultBytes 131072} :property {maxHistoryBytes 1048576} :property {maxResponseBytes 8388608} :property {maxOutputTokens 4096} :property {maxToolCalls 32} :property {maxApiRequests 16} :property {streamStore {}} :variable mutex :method init {} { if {${:streamStore} eq ""} { set :streamStore nsmcp:question-http:[ns_info server] } # ns_eval may construct backend copies in several interpreters. Every # copy draining/appending the same NSV stream must use the same lock. if {![nsv_exists nsmcp:question-http-locks ${:streamStore}] || ![nsv_get nsmcp:question-http-locks ${:streamStore} :mutex]} { set :mutex [nsv_set -default nsmcp:question-http-locks ${:streamStore} [ns_mutex create "nsmcp:question-http:[ns_info server]:[self]"]] } } # Describe non-secret provider settings to the administration interface. :public method describe {} { # # Describe the configured streaming chat-completions backend. # # Report provider settings and request limits without sending an API # request. # # @return The backend metadata dictionary. # return [dict create backend chat-completions model ${:model} apiUrl ${:apiUrl} streaming true timeout ${:timeout} maxOutputTokens ${:maxOutputTokens} maxToolCalls ${:maxToolCalls} maxApiRequests ${:maxApiRequests}] } :public method run {question state emit} { # # Execute a question through a temporary chat-completions runner. # # Forward the question, retained state and event callback; destroy the # runner on every exit. # # @param question Question text supplied to the selected provider. # @param state Opaque retained provider continuation or scan state. # @param emit Event callback prefix; returning false requests cancellation. # # @return The runner's completion or continuation result. # set runner [::nsmcp::ChatCompletionsRun new -backend [self] -emit $emit] try { return [$runner run $question $state] } finally { $runner destroy } } # The ns_http task callback runs in another interpreter. Keep only bounded # response bytes and status in NSV; parse SSE and invoke tools in the worker. :public method streamOpen {} { # # Allocate shared state for a streamed HTTP response. # # Create an independent response buffer and counters before registering # response callbacks. # # @return The new stream-state key. # set key [ns_crypto::randombytes -encoding hex 16] nsv_set ${:streamStore} $key {data {} total 0 status 0 contentType {} error {}} return $key } :public method streamHeaders {key fields} { # # Record streamed HTTP response headers. # # Update status and content type under the shared response-buffer mutex # while the stream remains active. # # @param key Retained stream or configuration key. # @param fields HTTP callback dictionary containing response status and # headers. # # @return The callback update result. # ns_mutex lock ${:mutex} try { if {[nsv_get ${:streamStore} $key record]} { dict set record status [dict get $fields status] dict set record contentType [ns_set iget [dict get $fields headers] content-type] nsv_set ${:streamStore} $key $record } } finally { ns_mutex unlock ${:mutex} } } :public method streamData {key fields} { # # Append bounded bytes from a streamed HTTP response. # # Serialize buffer and byte-counter updates and retain explicit # overflow/error state. # # @param key Retained stream or configuration key. # @param fields HTTP callback dictionary containing newly received data. # # @return The callback update result. # ns_mutex lock ${:mutex} try { if {[nsv_get ${:streamStore} $key record]} { set data [dict get $fields data] dict incr record total [string bytelength $data] if {[dict get $record total] > ${:maxResponseBytes} || [string bytelength [dict get $record data]] + [string bytelength $data] > 1048576} { dict set record error "API response exceeded its buffer or response size limit" } elseif {[dict get $record error] eq ""} { dict append record data $data } nsv_set ${:streamStore} $key $record } } finally { ns_mutex unlock ${:mutex} } # The request discards its normal output. Returning TCL_OK also works # with cores whose queued callback evaluator does not propagate BREAK. return } :public method streamDrain {key} { # # Drain currently buffered response bytes. # # Swap out buffered data under the shared mutex while retaining response # metadata and total-byte counters. # # @param key Retained stream or configuration key. # # @return The stream-state dictionary containing the drained data. # ns_mutex lock ${:mutex} try { set record [nsv_get ${:streamStore} $key] set next $record dict set next data {} nsv_set ${:streamStore} $key $next return $record } finally { ns_mutex unlock ${:mutex} } } :public method streamClose {key} { # # Release shared state for a completed or aborted stream. # # Remove the buffer entry under the mutex; tolerate a key already removed by # cleanup. # # @param key Retained stream or configuration key. # # @return The stream cleanup result. # ns_mutex lock ${:mutex} try { nsv_unset -nocomplain ${:streamStore} $key } finally { ns_mutex unlock ${:mutex} } }XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)