objectiveai_sdk/agent/mock/call.rs
1//! Deterministic-script override types for the mock agent.
2//!
3//! When [`super::AgentBase::calls`] is `Some(vec![Call{...}, ...])`,
4//! the mock agent skips its usual per-turn RNG response selection and
5//! instead emits each [`Call`] as its own assistant turn — every
6//! [`CallToolCall`] in `tool_calls` first (as tool-call deltas), then
7//! `content` (as content deltas) — in array order. Each subsequent
8//! turn walks the continuation to count how many [`Call`]s have
9//! already been satisfied; the next un-matched [`Call`] is what that
10//! turn emits. Once every [`Call`] has been satisfied, the mock falls
11//! through to its normal mode-driven dispatcher.
12
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15
16/// One scripted assistant turn for the mock agent's deterministic
17/// `calls` override (see [`super::AgentBase::calls`]).
18///
19/// When the mock fires this `Call`, it emits every entry in
20/// `tool_calls` first (as tool-call deltas), then `content` (as
21/// content deltas), finishing the turn after the last content chunk.
22/// The match check on the continuation compares
23/// `(tool_calls[i].name, tool_calls[i].arguments)` pairs plus the
24/// full `content` string — call ids are intentionally excluded since
25/// they're random per-emit.
26#[derive(
27 Clone,
28 Debug,
29 Default,
30 PartialEq,
31 Serialize,
32 Deserialize,
33 JsonSchema,
34 arbitrary::Arbitrary,
35)]
36#[schemars(rename = "agent.mock.Call")]
37pub struct Call {
38 /// Tool calls emitted by this turn. Empty `Vec` is allowed and
39 /// means "no tool calls, just content."
40 #[serde(default, skip_serializing_if = "Vec::is_empty")]
41 #[schemars(extend("omitempty" = true))]
42 pub tool_calls: Vec<CallToolCall>,
43
44 /// Assistant text content emitted *after* the tool calls. Plain
45 /// `String` — the mock's chunk-emission path only produces
46 /// `RichContent::Text`, so multimodal content was never possible
47 /// here anyway. An empty string is treated as "no content" by
48 /// the emitter (the wire shape becomes `content: None`) and
49 /// matches an assistant message with `content: None`.
50 pub content: String,
51}
52
53/// A single tool call within a [`Call`]. Identifies the tool by
54/// `name` and carries the exact JSON-encoded arguments to pass. No
55/// `id` field — call ids on the wire are minted randomly per emit
56/// and are ignored by the override's match check.
57#[derive(
58 Clone,
59 Debug,
60 Default,
61 PartialEq,
62 Serialize,
63 Deserialize,
64 JsonSchema,
65 arbitrary::Arbitrary,
66)]
67#[schemars(rename = "agent.mock.CallToolCall")]
68pub struct CallToolCall {
69 /// Tool name. Matched against the upstream tool surface at call
70 /// time the same way a model-emitted tool call would be.
71 pub name: String,
72 /// JSON-string arguments — same wire shape as
73 /// `AssistantToolCallFunction::arguments`. Passed through to the
74 /// emitted tool call verbatim; validation is the downstream
75 /// `tools/call` handler's job.
76 pub arguments: String,
77}