A scripted test provider that returns pre-configured responses in order.
Used for testing agent behavior without making HTTP calls. Start an Agent process with a list of responses, then pass its pid in the config.
Usage
{:ok, pid} = Alloy.Provider.Test.start_link([
Alloy.Provider.Test.text_response("Hello!"),
Alloy.Provider.Test.text_response("Goodbye!")
])
config = %{agent_pid: pid}
{:ok, resp1} = Alloy.Provider.Test.complete([msg], [], config)
# resp1 contains "Hello!"
{:ok, resp2} = Alloy.Provider.Test.complete([msg], [], config)
# resp2 contains "Goodbye!"
Summary
Functions
Pops the next scripted response from the agent.
Builds a scripted {:error, reason} response.
Builds a scripted response that sleeps for delay_ms milliseconds before
returning. Useful for testing that callers remain responsive during long
LLM turns.
Starts an Agent process holding the list of scripted responses.
Streams the next scripted response, calling on_chunk for each character
of text content. For tool_use responses, returns the response without
streaming. Consumes from the same script queue as complete/3.
Builds a scripted {:ok, completion_response} with a simple text reply.
Builds a scripted {:ok, completion_response} with text and provider state.
Builds a scripted response that emits a thinking delta via on_event, then
returns a retryable error. Used to test that chunks_emitted? tracks
on_event emissions so retries don't re-emit thinking deltas.
Builds a scripted {:ok, completion_response} with tool_use blocks.
Functions
Pops the next scripted response from the agent.
Ignores messages and tool_defs -- they exist only to satisfy the
behaviour callback. Config must contain :agent_pid.
Returns {:error, :no_more_responses} when all responses have been consumed.
Builds a scripted {:error, reason} response.
@spec slow_text_response(String.t(), non_neg_integer()) :: {:with_delay, non_neg_integer(), {:ok, Alloy.Provider.completion_response()}}
Builds a scripted response that sleeps for delay_ms milliseconds before
returning. Useful for testing that callers remain responsive during long
LLM turns.
@spec start_link(ok: Alloy.Provider.completion_response(), error: term()) :: {:ok, pid()}
Starts an Agent process holding the list of scripted responses.
Returns {:ok, pid} where the pid should be placed in the config
as :agent_pid.
Streams the next scripted response, calling on_chunk for each character
of text content. For tool_use responses, returns the response without
streaming. Consumes from the same script queue as complete/3.
@spec text_response(String.t()) :: {:ok, Alloy.Provider.completion_response()}
Builds a scripted {:ok, completion_response} with a simple text reply.
@spec text_response(String.t(), map()) :: {:ok, Alloy.Provider.completion_response()}
Builds a scripted {:ok, completion_response} with text and provider state.
Builds a scripted response that emits a thinking delta via on_event, then
returns a retryable error. Used to test that chunks_emitted? tracks
on_event emissions so retries don't re-emit thinking deltas.
@spec tool_use_response([Alloy.Message.content_block()]) :: {:ok, Alloy.Provider.completion_response()}
Builds a scripted {:ok, completion_response} with tool_use blocks.