> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# scripted • AI Agent SDK

> A scriptable model double for offline agent tests.

# scripted

AI Agent

A scriptable model double for offline agent tests.

:class:`ScriptedModel` stands in for a real provider so a unit test can assert
what an agent *does* -- "given this user turn, it calls `refund()` and then
stops" -- in milliseconds, with no network, no API key and no `unittest.mock`
patching of provider internals.

It is a real :class:`~praisonaiagents.llm.llm.LLM` subclass that replaces the
methods which talk to a provider and nothing else, so everything around the
call is the production code path: the system prompt is assembled normally,
tools are serialised to real schemas, scripted tool calls are dispatched
through the agent's own executor, and results are fed back as real tool
messages. Replies are built as genuine litellm response objects, so they are
parsed by the same code a live response would be.

Basic use::

from praisonaiagents import Agent
from praisonaiagents.model\_harness import ScriptedModel

model = ScriptedModel(\["Paris."])
agent = Agent(instructions="You are a geography bot.", llm=model)

assert agent.start("What is the capital of France?") == "Paris."
assert model.requests\[0].last\_user\_message == "What is the capital of France?"

Scripting a tool call followed by a final answer::

model = ScriptedModel(\[
ScriptedModel.tool\_call("refund", \{"order\_id": "A1"}),
"Refunded order A1.",
])
agent = Agent(instructions="Support bot.", llm=model, tools=\[refund])

assert agent.start("refund order A1") == "Refunded order A1."
assert model.request\_count == 2  # tool turn, then the follow-up

A script entry may also be a callable, which receives the
:class:`RecordedRequest` and returns a reply -- useful for replies that depend
on what the agent actually sent::

model = ScriptedModel(\[lambda req: f"You said: \{req.last\_user\_message}"])

When the agent asks for one more reply than the script holds, the double raises
:class:`ScriptExhausted` rather than hanging, looping or inventing an answer.

## Import

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.model_harness import scripted
```

## Classes

> **[ScriptedModelError](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/ScriptedModelError.md)**
>
> Base class for failures of the double itself.

> **[ScriptExhausted](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/ScriptExhausted.md)**
>
> Raised when an agent asks a :class:`ScriptedModel` for an unscripted reply.

> **[ScriptedToolCall](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/ScriptedToolCall.md)**
>
> One tool call the double should emit.

> **[ScriptedReply](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/ScriptedReply.md)**
>
> One assistant turn the double should return.

> **[RecordedRequest](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/RecordedRequest.md)**
>
> What the agent actually sent to the model on one turn.

> **[ScriptedModel](https://praison.ai/docs/sdk/reference/praisonaiagents/classes/ScriptedModel.md)**
>
> A model double that returns scripted replies in order and records requests.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.