Sagents.UserRequest (Sagents v0.17.1)

Copy Markdown

Groups a conversation's messages by the user request that caused them.

A user request starts when a human message lands in the conversation, stating something the user wants, and covers everything produced in response: assistant messages (thinking, narration, answers), tool calls and results, messages a tool queued or expanded into, and sub-agent work. It ends when the agent has nothing left to do for that request.

The user taking part along the way does not start a new request. Answering an ask_user question, approving or rejecting a tool call, and any other resume of an interrupt all serve the request that asked, and carry its number. Sending a new message instead of answering does start one, and the abandoned request is reported as :superseded.

User requests are numbered per conversation, starting at 1. Sagents.State.user_request_seq holds the current number, and every message carries the number it was produced under in metadata[:user_request_seq]. There is no stored user request record: everything here is derived from those stamps.

0 means no user request has started. Stamping with 0 leaves messages untouched.

A user request is not the same thing as a model turn (see LangChain.Message.continues_turn?/1) or a run (one Sagents.Agent.execute/3). One user request can span several runs and many model turns.

Summary

Functions

Return true when a message can be a user request's final answer: an assistant message with no tool calls that does not leave the model's turn open, and is not a summary standing in for older history.

Summarize one user request, or return nil when no message carries its number.

Summarize every user request whose messages are in the state, in order.

Set a message's user request number, replacing any it had.

Return the user request number a message was stamped with, or nil.

Stamp a message with seq unless it already has a number.

Stamp every message in a list that has no number yet. See stamp/2.

Stamp the messages inside a Sagents.Agent.execute/3 result. Results without a state pass through unchanged.

Stamp the messages of a state that have no number yet.

Build a summary from a user request's messages, given in conversation order.

Types

seq()

@type seq() :: non_neg_integer()

summary()

@type summary() :: %{
  seq: pos_integer(),
  messages: [LangChain.Message.t()],
  final_message: LangChain.Message.t() | nil,
  assistant_message_count: non_neg_integer(),
  tool_calls: %{required(String.t()) => pos_integer()},
  token_usage: LangChain.TokenUsage.t() | nil
}

Functions

final_answer?(message)

@spec final_answer?(LangChain.Message.t()) :: boolean()

Return true when a message can be a user request's final answer: an assistant message with no tool calls that does not leave the model's turn open, and is not a summary standing in for older history.

This is the question the chain asks to stop a run, asked at the user request boundary instead.

get(state, seq)

@spec get(Sagents.State.t(), pos_integer()) :: summary() | nil

Summarize one user request, or return nil when no message carries its number.

list(state)

@spec list(Sagents.State.t()) :: [summary()]

Summarize every user request whose messages are in the state, in order.

Summarization removes older messages from a state, so this only describes user requests whose messages are still present. A durable record belongs to the host, written when each user request completes.

put_seq(message, seq)

Set a message's user request number, replacing any it had.

seq(message)

@spec seq(LangChain.Message.t()) :: pos_integer() | nil

Return the user request number a message was stamped with, or nil.

stamp(message, seq)

Stamp a message with seq unless it already has a number.

A message keeps the number it was first stamped with, so stamping the same message again, at any later point, changes nothing. A seq of 0 leaves the message untouched.

stamp_all(messages, seq)

@spec stamp_all([LangChain.Message.t()], seq()) :: [LangChain.Message.t()]

Stamp every message in a list that has no number yet. See stamp/2.

stamp_result(other, seq)

@spec stamp_result(term(), seq()) :: term()

Stamp the messages inside a Sagents.Agent.execute/3 result. Results without a state pass through unchanged.

stamp_state(state, seq)

@spec stamp_state(Sagents.State.t(), seq()) :: Sagents.State.t()

Stamp the messages of a state that have no number yet.

summarize(seq, messages)

@spec summarize(pos_integer(), [LangChain.Message.t()]) :: summary()

Build a summary from a user request's messages, given in conversation order.

token_usage is the total across the messages: each message's own usage plus any sub-agent usage recorded on it. It includes the usage of summarization calls the user request triggered.