send

suspend fun send(message: UserMessage, parameters: RunAgentParameters? = null): RunState

Appends message to the transcript, sends it with the thread's history, and runs the agent.

This is how a client says something. run cannot: RunAgentParameters carries a run id, tools, context and forwarded properties and no messages, and AbstractAgent.setMessages is protected -- so through that path the only messages a server ever sees are the ones the agent was constructed with plus the ones its own runs produced. The public way in is the RunAgentInput overload of runAgentObservable, which the agent then adopts as its own state (messages and state are assigned from the input), so the turn sent here is history for every run after it.

The history sent is the agent's own, which is the agent's own accounting of the thread and not this transcript: upstream folds each run's answer back into messages, in the lossy shape its state layer keeps, and that is the shape the protocol asks a client to send back. The transcript is for the screen and keeps the ordering that shape loses.

The message reaches the transcript before the run starts, under the session's own lock, so the sender sees their line before the answer to it and no other run can slip events between the two. It is the lock, not the clock: a send that arrives while an earlier run is still streaming waits for that run, and nothing of this turn is on screen until it does.

A run that fails leaves the message there -- what was said was said, and a UI that offers a retry needs it on screen to retry from. Retry through run, not through a second send. The turn is already the agent's history by then: runAgentObservable adopts the input's messages before the run that fails, so run asks the same question again, while a second send would append it a second time and the server would be asked twice.

With a tools registry, a run that calls one of its tools is answered by another run, and this returns the state the last of those ended in; see the class note. A tool result an earlier run failed to carry goes out with this one, ahead of message.

The input is built here rather than by AbstractAgent.prepareRunAgentInput, which is the one thing this path cannot reuse -- it takes RunAgentParameters, which is what carries no messages. Field for field it is defaulted the way that method defaults them, but it is not that method: an agent that overrides it to add something of its own gets that on run and not here.

Parameters

message

the turn to send. Supply the id when the client has one to supply; it is the id the message goes on the wire with, and the one it is drawn under unless the transcript already holds that id, in which case the drawn one is suffixed and the wire's is not (see UiTranscriptReducer.appendUserMessage). A later MESSAGES_SNAPSHOT does not reconcile against it either -- a snapshot replaces the transcript whole, the server's copy of this turn included. A thread that is interrupted may not be sent to, as it may not be run: this throws before the message reaches the transcript, so a line the thread cannot carry is neither drawn nor failed. Answer the interrupts with resume first. As with run, a failed resume's answers are carried again rather than refused.

parameters

the run's id, tools, context and forwarded properties. Defaulted here the way AbstractAgent defaults them: a generated run id, no tools, no context, and empty forwarded properties. The registry's tools, when there is one, are declared after the caller's.

Throws

when the thread is interrupted and no failed resume is owed.


suspend fun send(text: String, parameters: RunAgentParameters? = null): RunState

Sends one line of text as a user turn, under a generated message id.

The id is this library's rather than the caller's, which is the trade: a chat box that has nothing to say about ids does not have to invent a scheme, and a client that does -- one matching messages against a store of its own -- passes a UserMessage to send instead.