// Tool calls: what the model asked to run, what it produced, and the permission prompt around it.
///|
/// What kind of thing a tool does, for a client that wants to pick an icon.
#derive(Eq)
pub(all) enum ToolKind {
Read
Edit
Delete
Move
Search
Execute
Think
Fetch
SwitchMode
Other
}
///|
pub extend ToolKind with Eq::{equal, not_equal}
///|
/// The name the kind travels as.
pub fn ToolKind::to_string(self : ToolKind) -> String {
match self {
Read => "read"
Edit => "edit"
Delete => "delete"
Move => "move"
Search => "search"
Execute => "execute"
Think => "think"
Fetch => "fetch"
SwitchMode => "switch_mode"
Other => "other"
}
}
///|
/// The kind with that name, or `None`.
pub fn ToolKind::of(name : String) -> ToolKind? {
match name {
"read" => Some(Read)
"edit" => Some(Edit)
"delete" => Some(Delete)
"move" => Some(Move)
"search" => Some(Search)
"execute" => Some(Execute)
"think" => Some(Think)
"fetch" => Some(Fetch)
"switch_mode" => Some(SwitchMode)
"other" => Some(Other)
_ => None
}
}
///|
pub extend ToolKind with @json.ToJson::{to_json}
///|
pub impl ToJson for ToolKind with fn to_json(self) {
Json::string(self.to_string())
}
///|
pub extend ToolKind with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ToolKind with fn from_json(json, path) {
match ToolKind::of(text_of(json, path)) {
Some(kind) => kind
None => raise want(path, "a tool kind", json)
}
}
///|
/// How far a tool call got.
#derive(Eq)
pub(all) enum ToolCallStatus {
Pending
InProgress
Completed
Failed
}
///|
pub extend ToolCallStatus with Eq::{equal, not_equal}
///|
/// The name the status travels as.
pub fn ToolCallStatus::to_string(self : ToolCallStatus) -> String {
match self {
Pending => "pending"
InProgress => "in_progress"
Completed => "completed"
Failed => "failed"
}
}
///|
/// The status with that name, or `None`.
pub fn ToolCallStatus::of(name : String) -> ToolCallStatus? {
match name {
"pending" => Some(Pending)
"in_progress" => Some(InProgress)
"completed" => Some(Completed)
"failed" => Some(Failed)
_ => None
}
}
///|
pub extend ToolCallStatus with @json.ToJson::{to_json}
///|
pub impl ToJson for ToolCallStatus with fn to_json(self) {
Json::string(self.to_string())
}
///|
pub extend ToolCallStatus with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ToolCallStatus with fn from_json(json, path) {
match ToolCallStatus::of(text_of(json, path)) {
Some(status) => status
None => raise want(path, "a tool call status", json)
}
}
///|
/// A tool call the model has asked for.
#derive(Eq)
pub(all) struct ToolCall {
tool_call_id : String
title : String
name : String?
kind : ToolKind?
status : ToolCallStatus?
content : Array[ToolCallContent]?
locations : Array[ToolCallLocation]?
raw_input : Json?
raw_output : Json?
meta : Json?
}
///|
pub extend ToolCall with Eq::{equal, not_equal}
///|
pub extend ToolCall with @json.ToJson::{to_json}
///|
pub impl ToJson for ToolCall with fn to_json(self) {
json_of([
("toolCallId", Some(Json::string(self.tool_call_id))),
("title", Some(Json::string(self.title))),
("name", json_string(self.name)),
("kind", self.kind.map(write)),
("status", self.status.map(write)),
("content", json_list_of(self.content)),
("locations", json_list_of(self.locations)),
("rawInput", self.raw_input),
("rawOutput", self.raw_output),
("_meta", self.meta),
])
}
///|
pub extend ToolCall with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ToolCall with fn from_json(json, path) {
let fields = expect_object(json, path)
{
tool_call_id: required_string(fields, "toolCallId", path),
title: required_string(fields, "title", path),
name: string_member(fields, "name", path),
kind: enum_member(fields, "kind", path, ToolKind::of),
status: enum_member(fields, "status", path, ToolCallStatus::of),
content: list_member(fields, "content", path, (value, at) => read(value, at)),
locations: list_member(fields, "locations", path, (value, at) => {
read(value, at)
}),
raw_input: field_of(fields, "rawInput", path),
raw_output: field_of(fields, "rawOutput", path),
meta: meta_of(fields, path),
}
}
///|
/// A later change to a tool call: only what changed is present.
#derive(Eq)
pub(all) struct ToolCallUpdate {
tool_call_id : String
kind : ToolKind?
status : ToolCallStatus?
title : String?
name : String?
content : Array[ToolCallContent]?
locations : Array[ToolCallLocation]?
raw_input : Json?
raw_output : Json?
meta : Json?
}
///|
pub extend ToolCallUpdate with Eq::{equal, not_equal}
///|
pub extend ToolCallUpdate with @json.ToJson::{to_json}
///|
pub impl ToJson for ToolCallUpdate with fn to_json(self) {
json_of([
("toolCallId", Some(Json::string(self.tool_call_id))),
("kind", self.kind.map(write)),
("status", self.status.map(write)),
("title", json_string(self.title)),
("name", json_string(self.name)),
("content", json_list_of(self.content)),
("locations", json_list_of(self.locations)),
("rawInput", self.raw_input),
("rawOutput", self.raw_output),
("_meta", self.meta),
])
}
///|
pub extend ToolCallUpdate with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ToolCallUpdate with fn from_json(json, path) {
let fields = expect_object(json, path)
{
tool_call_id: required_string(fields, "toolCallId", path),
kind: enum_member(fields, "kind", path, ToolKind::of),
status: enum_member(fields, "status", path, ToolCallStatus::of),
title: string_member(fields, "title", path),
name: string_member(fields, "name", path),
content: list_member(fields, "content", path, (value, at) => read(value, at)),
locations: list_member(fields, "locations", path, (value, at) => {
read(value, at)
}),
raw_input: field_of(fields, "rawInput", path),
raw_output: field_of(fields, "rawOutput", path),
meta: meta_of(fields, path),
}
}
///|
/// What choosing an option means, so a client can group the buttons.
#derive(Eq)
pub(all) enum PermissionOptionKind {
AllowOnce
AllowAlways
RejectOnce
RejectAlways
}
///|
pub extend PermissionOptionKind with Eq::{equal, not_equal}
///|
/// The name the option kind travels as.
pub fn PermissionOptionKind::to_string(self : PermissionOptionKind) -> String {
match self {
AllowOnce => "allow_once"
AllowAlways => "allow_always"
RejectOnce => "reject_once"
RejectAlways => "reject_always"
}
}
///|
/// The option kind with that name, or `None`.
pub fn PermissionOptionKind::of(name : String) -> PermissionOptionKind? {
match name {
"allow_once" => Some(AllowOnce)
"allow_always" => Some(AllowAlways)
"reject_once" => Some(RejectOnce)
"reject_always" => Some(RejectAlways)
_ => None
}
}
///|
pub extend PermissionOptionKind with @json.ToJson::{to_json}
///|
pub impl ToJson for PermissionOptionKind with fn to_json(self) {
Json::string(self.to_string())
}
///|
pub extend PermissionOptionKind with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for PermissionOptionKind with fn from_json(json, path) {
match PermissionOptionKind::of(text_of(json, path)) {
Some(kind) => kind
None => raise want(path, "a permission option kind", json)
}
}
///|
/// One button in a permission prompt.
#derive(Eq)
pub(all) struct PermissionOption {
option_id : String
name : String
kind : PermissionOptionKind
meta : Json?
}
///|
pub extend PermissionOption with Eq::{equal, not_equal}
///|
pub extend PermissionOption with @json.ToJson::{to_json}
///|
pub impl ToJson for PermissionOption with fn to_json(self) {
json_of([
("optionId", Some(Json::string(self.option_id))),
("name", Some(Json::string(self.name))),
("kind", Some(write(self.kind))),
("_meta", self.meta),
])
}
///|
pub extend PermissionOption with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for PermissionOption with fn from_json(json, path) {
let fields = expect_object(json, path)
{
option_id: required_string(fields, "optionId", path),
name: required_string(fields, "name", path),
kind: required_enum(fields, "kind", path, PermissionOptionKind::of),
meta: meta_of(fields, path),
}
}
///|
/// The ask the agent makes: run this tool call, and here is what the user may choose.
#derive(Eq)
pub(all) struct Permission {
tool_call : ToolCallUpdate
options : Array[PermissionOption]
meta : Json?
}
///|
pub extend Permission with Eq::{equal, not_equal}
///|
pub extend Permission with @json.ToJson::{to_json}
///|
pub impl ToJson for Permission with fn to_json(self) {
json_of([
("toolCall", Some(write(self.tool_call))),
("options", Some(Json::array(self.options.map(write)))),
("_meta", self.meta),
])
}
///|
pub extend Permission with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for Permission with fn from_json(json, path) {
let fields = expect_object(json, path)
{
tool_call: required_object(fields, "toolCall", path),
options: required_objects(fields, "options", path),
meta: meta_of(fields, path),
}
}
///|
/// What came back: one option chosen, or the ask dismissed.
#derive(Eq)
pub(all) enum Outcome {
Selected(String)
Cancelled
}
///|
pub extend Outcome with Eq::{equal, not_equal}
///|
pub extend Outcome with @json.ToJson::{to_json}
///|
pub impl ToJson for Outcome with fn to_json(self) {
match self {
Selected(option_id) =>
json_tagged(
json_of([("optionId", Some(Json::string(option_id)))]),
"outcome",
"selected",
)
Cancelled => json_tagged(Json::empty_object(), "outcome", "cancelled")
}
}
///|
pub extend Outcome with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for Outcome with fn from_json(json, path) {
let fields = expect_object(json, path)
match required_string(fields, "outcome", path) {
"selected" => Selected(required_string(fields, "optionId", path))
"cancelled" => Cancelled
other =>
raise @json.JsonDecodeError(
(path.add_key("outcome"), "unknown outcome \{other}"),
)
}
}