Scanner API
Scanner
Scanner
Scan transcript content.
class Scanner(Protocol[T]):
def __call__(self, input: T, /) -> Awaitable[Result | list[Result]]inputT-
Input to scan.
ScannerInput
Union of all valid scanner input types.
ScannerInput = Union[
Transcript,
ChatMessage,
Sequence[ChatMessage],
Event,
Sequence[Event],
]Result
Scan result.
class Result(BaseModel)Attributes
uuidstr | None-
Unique identifer for scan result.
valueJsonValue-
Scan value.
answerstr | None-
Answer extracted from model output (optional)
explanationstr | None-
Explanation of result (optional).
metadatadict[str, Any] | None-
Additional metadata related to the result (optional)
referenceslist[Reference]-
References to relevant messages or events.
labelstr | None-
Label for result to indicate its origin.
typestr | None-
Type to designate contents of ‘value’ (used in
value_typefield in result data frames).
Reference
Reference to scanned content.
class Reference(BaseModel)Attributes
typeLiteral['message', 'event']-
Reference type.
citestr | None-
Cite text used when the entity was referenced (optional).
For example, a model may have pointed to a message using something like [M22], which is the cite.
idstr-
Reference id (message or event id)
Error
Scan error (runtime error which occurred during scan).
class Error(BaseModel)Attributes
transcript_idstr-
Target transcript id.
scannerstr-
Scanner name.
errorstr-
Error message.
tracebackstr-
Error traceback.
Loader
Load transcript data.
class Loader(Protocol[TLoaderResult]):
def __call__(
self,
transcript: Transcript,
) -> AsyncIterator[TLoaderResult]transcriptTranscript-
Transcript to yield from.
LLM Scanner
llm_scanner
Create a scanner that uses an LLM to scan transcripts.
This scanner presents a conversation transcript to an LLM along with a custom prompt and answer specification, enabling automated analysis of conversations for specific patterns, behaviors, or outcomes.
@scanner(messages="all")
def llm_scanner(
*,
question: str | Callable[[Transcript], Awaitable[str]],
answer: Literal["boolean", "numeric", "string"]
| list[str]
| AnswerMultiLabel
| AnswerStructured,
template: str | None = None,
template_variables: dict[str, Any]
| Callable[[Transcript], dict[str, Any]]
| None = None,
preprocessor: MessagesPreprocessor | None = None,
model: str | Model | None = None,
name: str | None = None,
) -> Scanner[Transcript]questionstr | Callable[[Transcript], Awaitable[str]]-
Question for the scanner to answer. Can be a static string (e.g., “Did the assistant refuse the request?”) or a function that takes a Transcript and returns an string for dynamic questions based on transcript content.
answerLiteral['boolean', 'numeric', 'string'] | list[str] | AnswerMultiLabel | AnswerStructured-
Specification of the answer format. Pass “boolean”, “numeric”, or “string” for a simple answer; pass
list[str]for a set of labels; or passMultiLabelsfor multi-classification. templatestr | None-
Overall template for scanner prompt. The scanner template should include the following variables: - {{ question }} (question for the model to answer) - {{ messages }} (transcript message history as string) - {{ answer_prompt }} (prompt for a specific type of answer). - {{ answer_format }} (instructions on how to format the answer) In addition, scanner templates can bind to any data with the Transcript being processes (e.g. {{ transcript.score }})
template_variablesdict[str, Any] | Callable[[Transcript], dict[str, Any]] | None-
Additional variables to make available in the template. Optionally takes a function which receives the current Transcript which can return variables.
preprocessorMessagesPreprocessor | None-
Transform conversation messages before analysis. Controls exclusion of system messages, reasoning tokens, and tool calls. Defaults to removing system messages.
modelstr | Model | None-
Optional model specification. Can be a model name string or
Model instance. If None, uses the default model namestr | None-
Scanner name. Use this to assign a name when passing llm_scanner() directly to scan() rather than delegating to it from another scanner.
AnswerMultiLabel
Label descriptions for LLM scanner multi-classification.
class AnswerMultiLabel(NamedTuple)Attributes
labelslist[str]-
List of label descriptions.
Label values (e.g. A, B, C) will be provided automatically.
Utils
messages_as_str
Concatenate list of chat messages into a string.
async def messages_as_str(
messages: list[ChatMessage],
*,
preprocessor: MessagesPreprocessor | None = None,
include_ids: Literal[True] | None = None,
) -> str | tuple[str, Callable[[str], list[Reference]]]messageslist[ChatMessage]-
List of chat messages.
preprocessorMessagesPreprocessor | None-
Content filter for messages.
include_idsLiteral[True] | None-
If True, prepend ordinal references (e.g., [M1], [M2]) to each message and return a function to extract references from text. If None (default), return plain formatted string.
MessagesPreprocessor
ChatMessage preprocessing transformations.
Provide a transform function for fully custom transformations. Use the higher-level options (e.g. exclude_system) to perform varioius common content removal transformations.
The default MessagesPreprocessor will exclude system messages and do no other transformations.
class MessagesPreprocessor(NamedTuple)Attributes
transformCallable[[list[ChatMessage]], Awaitable[list[ChatMessage]]] | None-
Transform the list of messages.
exclude_systembool-
Exclude system messages (defaults to
True) exclude_reasoningbool-
Exclude reasoning content (defaults to
False). exclude_tool_usagebool-
Exclude tool usage (defaults to
False)
Types
MessageType
Message types.
MessageType = Literal["system", "user", "assistant", "tool"]EventType
Event types.
EventType = Literal[
"model",
"tool",
"approval",
"sandbox",
"info",
"logger",
"error",
"span_begin",
"span_end",
]Registration
scanner
Decorator for registering scanners.
def scanner(
factory: ScannerFactory[P, T] | None = None,
*,
loader: Loader[TScan] | None = None,
messages: list[MessageType] | Literal["all"] | None = None,
events: list[EventType] | Literal["all"] | None = None,
name: str | None = None,
metrics: Sequence[Metric | Mapping[str, Sequence[Metric]]]
| Mapping[str, Sequence[Metric]]
| None = None,
) -> (
ScannerFactory[P, T]
| Callable[[ScannerFactory[P, T]], ScannerFactory[P, T]]
| Callable[[ScannerFactory[P, TScan]], ScannerFactory[P, TScan]]
| Callable[[ScannerFactory[P, TM]], ScannerFactory[P, ScannerInput]]
| Callable[[ScannerFactory[P, TE]], ScannerFactory[P, ScannerInput]]
)factoryScannerFactory[P, T] | None-
Decorated scanner function.
loaderLoader[TScan] | None-
Custom data loader for scanner.
messageslist[MessageType] | Literal['all'] | None-
Message types to scan.
eventslist[EventType] | Literal['all'] | None-
Event types to scan.
namestr | None-
Scanner name (defaults to function name).
metricsSequence[Metric | Mapping[str, Sequence[Metric]]] | Mapping[str, Sequence[Metric]] | None-
One or more metrics to calculate over the values (only used if scanner is converted to a scorer via as_scorer()).
loader
Decorator for registering loaders.
def loader(
*,
name: str | None = None,
messages: list[MessageType] | Literal["all"] | None = None,
events: list[EventType] | Literal["all"] | None = None,
content: TranscriptContent | None = None,
) -> Callable[[LoaderFactory[P, TLoaderResult]], LoaderFactory[P, TLoaderResult]]namestr | None-
Loader name (defaults to function name).
messageslist[MessageType] | Literal['all'] | None-
Message types to load from.
eventslist[EventType] | Literal['all'] | None-
Event types to load from.
contentTranscriptContent | None-
Transcript content filter.
as_scorer
Convert a Scanner to an Inspect Scorer.
def as_scorer(
scanner: Scanner[Transcript],
metrics: Sequence[Metric | Mapping[str, Sequence[Metric]]]
| Mapping[str, Sequence[Metric]]
| None = None,
) -> ScorerscannerScanner[Transcript]-
Scanner to convert (must take a Transcript).
metricsSequence[Metric | Mapping[str, Sequence[Metric]]] | Mapping[str, Sequence[Metric]] | None-
Metrics for scorer. Defaults to
metricsspecified on the@scannerdecorator (or[accuracy(), stderr()]if none were specified).