1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
type role = System | User | Assistant | Tool
type tool_call = { id : string; name : string; arguments_json : string }
type t = {
role : role;
content : string;
name : string option;
tool_call_id : string option;
tool_result_error : bool option;
tool_calls : tool_call list;
metadata : (string * Chatoyant_runtime.Json.t) list;
}
let make ?name ?tool_call_id ?tool_result_error ?(tool_calls = [])
?(metadata = []) role content =
{ role; content; name; tool_call_id; tool_result_error; tool_calls; metadata }
let system content = make System content
let user content = make User content
let assistant content = make Assistant content
let assistant_with_tool_calls ?(content = "") calls =
let tool_calls =
List.map
(fun (call : Chatoyant_provider.Provider.tool_call) ->
{ id = call.id; name = call.name; arguments_json = call.arguments_json })
calls
in
make ~tool_calls Assistant content
let tool ?is_error ~tool_call_id content =
make ?tool_result_error:is_error ~tool_call_id Tool content
let has_tool_calls message = message.tool_calls <> []
let role_to_string = function
| System -> "system"
| User -> "user"
| Assistant -> "assistant"
| Tool -> "tool"
let role_of_string = function
| "system" -> Some System
| "user" -> Some User
| "assistant" -> Some Assistant
| "tool" -> Some Tool
| _ -> None
let to_provider_role = function
| System -> Chatoyant_provider.Provider.System
| User -> Chatoyant_provider.Provider.User
| Assistant -> Chatoyant_provider.Provider.Assistant
| Tool -> Chatoyant_provider.Provider.Tool
let to_provider_message message =
let tool_calls =
List.map
(fun (call : tool_call) ->
let arguments =
match Chatoyant_runtime.Json.parse call.arguments_json with
| Ok json -> json
| Error _ -> Chatoyant_runtime.Json.Null
in
{
Chatoyant_provider.Provider.id = call.id;
name = call.name;
arguments;
arguments_json = call.arguments_json;
raw = None;
})
message.tool_calls
in
{
Chatoyant_provider.Provider.role = to_provider_role message.role;
content = Some message.content;
name = message.name;
tool_call_id = message.tool_call_id;
tool_calls;
tool_result_error = message.tool_result_error;
}
let string value = Chatoyant_runtime.Json.String value
let add_opt name value fields =
match value with None -> fields | Some value -> (name, value) :: fields
let tool_call_to_json call =
Chatoyant_runtime.Json.Object
[
("id", string call.id);
("name", string call.name);
("arguments_json", string call.arguments_json);
]
let metadata_to_json metadata = Chatoyant_runtime.Json.Object metadata
let to_json message =
[
("role", string (role_to_string message.role));
("content", string message.content);
( "tool_calls",
Chatoyant_runtime.Json.Array
(List.map tool_call_to_json message.tool_calls) );
("metadata", metadata_to_json message.metadata);
]
|> add_opt "name" (Option.map string message.name)
|> add_opt "tool_call_id" (Option.map string message.tool_call_id)
|> add_opt "tool_result_error"
(Option.map
(fun value -> Chatoyant_runtime.Json.Bool value)
message.tool_result_error)
|> List.rev
|> fun fields -> Chatoyant_runtime.Json.Object fields
let field = Chatoyant_runtime.Json.field
let string_field name json =
Option.bind (field name json) Chatoyant_runtime.Json.as_string
let tool_call_of_json json =
match
( string_field "id" json,
string_field "name" json,
string_field "arguments_json" json )
with
| Some id, Some name, Some arguments_json -> Ok { id; name; arguments_json }
| _ -> Error "invalid message tool call JSON"
let metadata_of_json json =
match field "metadata" json with
| Some (Chatoyant_runtime.Json.Object fields) -> fields
| _ -> []
let of_json json =
match Option.bind (string_field "role" json) role_of_string with
| None -> Error "invalid message role"
| Some role -> (
let content = Option.value (string_field "content" json) ~default:"" in
let tool_calls =
match field "tool_calls" json with
| Some (Chatoyant_runtime.Json.Array values) ->
let rec loop acc = function
| [] -> Ok (List.rev acc)
| value :: rest -> (
match tool_call_of_json value with
| Ok call -> loop (call :: acc) rest
| Error _ as err -> err)
in
loop [] values
| _ -> Ok []
in
match tool_calls with
| Error _ as err -> err
| Ok tool_calls ->
Ok
{
role;
content;
name = string_field "name" json;
tool_call_id = string_field "tool_call_id" json;
tool_result_error =
Option.bind
(field "tool_result_error" json)
Chatoyant_runtime.Json.as_bool;
tool_calls;
metadata = metadata_of_json json;
})