nsmcp::QuestionService method send (public)
<instance of nsmcp::QuestionService> send context question \ [ handle ] [ backendName ] [ browserTimezone ] [ peerAddress ] \ [ expectedTurn ] [ backendQuestion ] [ continuedFrom ]
Defined in /usr/local/ns/tcl/nsmcp/question-service.tcl
Queue a question or follow-up with optional browser timezone context.
- Parameters:
- context (required)
- Authenticated owner and server context.
- question (required)
- Original question text, preserved for display.
- handle (optional)
- Existing conversation handle, or empty for a new conversation.
- backendName (optional)
- Backend selection for a new conversation, or empty for its default.
- browserTimezone (optional)
- Valid timezone used as the default unless the question overrides it; empty retains prior context or UTC.
- peerAddress (optional)
- Direct connection peer supplied by the authenticated HTTP handler, or empty for non-HTTP callers.
- expectedTurn (optional)
- Optional internal guard against continuing a superseded turn.
- backendQuestion (optional)
- Optional server-generated backend task, separate from the displayed question.
- continuedFrom (optional)
- Owned source turn for editing the original request.
- Returns:
- Rooted JSON triples describing the queued conversation.
- Testcases:
- No testcase defined.
Source code: if {$browserTimezone ne "" && (![regexp {^[A-Za-z0-9_+:/-]{1,128}$} $browserTimezone] || [catch {clock format 0 -timezone $browserTimezone}])} { error "Invalid browser timezone" } if {$peerAddress ne "" && ![ns_ip valid $peerAddress]} {error "Invalid question peer address"} set question [string trim $question] if {$question eq "" || [string bytelength $question] > 16384} {error "Supply a question up to 16 KiB"} if {$backendQuestion ne {} && ([string bytelength $backendQuestion]>16384 || $expectedTurn eq {} || $continuedFrom eq {})} {error "Invalid internal continuation task"} ns_mutex lock ${:mutex} try { if {$handle eq ""} { :cleanup foreach key [nsv_array names ${:store}] { set old [nsv_get ${:store} $key] if {[dict get $old expires] <= [clock seconds] && [dict get $old status] ni {queued running cancelling}} { :drop $key } } if {[llength [nsv_array names ${:store}]] >= ${:maxConversations}} {error "Conversation limit reached; remove an old conversation"} if {$backendName eq ""} {set backendName [:defaultBackend]} :provider $backendName set handle [ns_crypto::randombytes -encoding hex 32] set record [dict create principal [$context principal] server [$context server] backend $backendName status idle state {} turns {}] } else { set record [:owned $context $handle] if {![dict exists $record backend]} {dict set record backend [:defaultBackend]} if {$backendName ne "" && $backendName ne [dict get $record backend]} { error "Changing backend requires a new conversation" } } if {$backendQuestion ne {}} { set ownedSource false foreach entry [dict get $record turns] {if {[dict get $entry id] eq $continuedFrom} {set ownedSource true; break}} if {!$ownedSource} {error "Continuation source is not in this conversation"} } if {$expectedTurn ne "" && [dict get $record current] ne $expectedTurn} { error "The conversation has moved on; refresh its status before continuing" } if {[dict get $record status] in {queued running cancelling}} {error "A question is already running in this conversation"} if {[llength [dict get $record turns]] >= ${:maxTurns}} {error "Conversation turn limit reached; start a new conversation"} if {$browserTimezone ne ""} {dict set record browserTimezone $browserTimezone} set turn [ns_crypto::randombytes -encoding hex 16] dict set record current $turn dict set record status queued dict set record expires [expr {[clock seconds]+int(${:lifetime})}] set description [[:provider [dict get $record backend]] describe] set model {} if {[dict exists $description model]} {set model [dict get $description model]} set last [dict create id $turn conversation $handle question $question answer {} status queued tools {} error {} peerAddress $peerAddress peerSource [expr {$peerAddress eq "" ? "unavailable" : "direct"}] submittedAt [clock seconds] submittedMs [clock milliseconds] requestedModel $model] if {$backendQuestion ne {}} {dict set last backendQuestion $backendQuestion; dict set last continuedFrom $continuedFrom} if {[dict exists $description backend] && [dict get $description backend] eq "codex"} { dict set last questionUsage {source codex scope turn available false reason no-provider-usage} } dict lappend record turns $last :logQuestion submitted $record $last nsv_set ${:store} $handle $record try { ns_job queue -detached ${:queue} [list [self] run $handle $turn] } on error {message options} { dict set record status failed set last [lindex [dict get $record turns] end] dict set last status failed dict set last error "Unable to queue the question" dict set record turns [lreplace [dict get $record turns] end end $last] nsv_set ${:store} $handle $record :logQuestion finished $record $last return -options $options $message } } finally {ns_mutex unlock ${:mutex}} return [:poll $context $handle]XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)