/ template_tests / hermes_template_test.ipynb
hermes_template_test.ipynb
1 { 2 "cells": [ 3 { 4 "cell_type": "code", 5 "execution_count": null, 6 "metadata": {}, 7 "outputs": [], 8 "source": [ 9 "%pip install --upgrade --quiet transformers" 10 ] 11 }, 12 { 13 "cell_type": "code", 14 "execution_count": 1, 15 "metadata": {}, 16 "outputs": [ 17 { 18 "name": "stderr", 19 "output_type": "stream", 20 "text": [ 21 "/home/interstellarninja/miniforge3/envs/hermes-tools/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", 22 " from .autonotebook import tqdm as notebook_tqdm\n", 23 "None of PyTorch, TensorFlow >= 2.0, or Flax have been found. Models won't be available and only tokenizers, configuration and file/data utilities can be used.\n" 24 ] 25 } 26 ], 27 "source": [ 28 "from transformers import AutoTokenizer, AutoModelForCausalLM\n", 29 "\n", 30 "model_path = \"NousResearch/Hermes-3-Llama-3.1-8B\"\n", 31 "#model_path = \"NousResearch/Hermes-2-Pro-Llama-3-8B\"\n", 32 "tokenizer = AutoTokenizer.from_pretrained(model_path)" 33 ] 34 }, 35 { 36 "cell_type": "code", 37 "execution_count": 2, 38 "metadata": {}, 39 "outputs": [], 40 "source": [ 41 "from pydantic import BaseModel\n", 42 "from typing import Any\n", 43 "import re\n", 44 "import json\n", 45 "\n", 46 "class FunctionCall(BaseModel):\n", 47 " name: str\n", 48 " arguments: dict[str, Any]" 49 ] 50 }, 51 { 52 "cell_type": "code", 53 "execution_count": 3, 54 "metadata": {}, 55 "outputs": [ 56 { 57 "name": "stdout", 58 "output_type": "stream", 59 "text": [ 60 "{\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"arguments\": {\"title\": \"Arguments\", \"type\": \"object\"}}, \"required\": [\"name\", \"arguments\"], \"title\": \"FunctionCall\", \"type\": \"object\"}\n" 61 ] 62 } 63 ], 64 "source": [ 65 "print(FunctionCall.schema_json())" 66 ] 67 }, 68 { 69 "cell_type": "code", 70 "execution_count": 4, 71 "metadata": {}, 72 "outputs": [], 73 "source": [ 74 "template_str = \"\"\"{%- macro json_to_python_type(json_spec) %}\n", 75 "{%- set basic_type_map = {\n", 76 " \"string\": \"str\",\n", 77 " \"number\": \"float\",\n", 78 " \"integer\": \"int\",\n", 79 " \"boolean\": \"bool\"\n", 80 "} %}\n", 81 "\n", 82 "{%- if basic_type_map[json_spec.type] is defined %}\n", 83 " {{- basic_type_map[json_spec.type] }}\n", 84 "{%- elif json_spec.type == \"array\" %}\n", 85 " {{- \"list[\" + json_to_python_type(json_spec|items) + \"]\"}}\n", 86 "{%- elif json_spec.type == \"object\" %}\n", 87 " {%- if json_spec.additionalProperties is defined %}\n", 88 " {{- \"dict[str, \" + json_to_python_type(json_spec.additionalProperties) + ']'}}\n", 89 " {%- else %}\n", 90 " {{- \"dict\" }}\n", 91 " {%- endif %}\n", 92 "{%- elif json_spec.type is iterable %}\n", 93 " {{- \"Union[\" }}\n", 94 " {%- for t in json_spec.type %}\n", 95 " {{- json_to_python_type({\"type\": t}) }}\n", 96 " {%- if not loop.last %}\n", 97 " {{- \",\" }} \n", 98 " {%- endif %}\n", 99 " {%- endfor %}\n", 100 " {{- \"]\" }}\n", 101 "{%- else %}\n", 102 " {{- \"Any\" }}\n", 103 "{%- endif %}\n", 104 "{%- endmacro %}\n", 105 "\n", 106 "\n", 107 "{{- bos_token }}\n", 108 "{{- '<|im_start|>system\n", 109 "' }}\n", 110 "{{- \"You are a function calling AI model. You are provided with function signatures within <tools></tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: <tools> \" }}\n", 111 "{%- for tool in tools %}\n", 112 " {%- if tool.function is defined %}\n", 113 " {%- set tool = tool.function %}\n", 114 " {%- endif %}\n", 115 " {{- '{\"type\": \"function\", \"function\": ' }}\n", 116 " {{- '{\"name\": \"' + tool.name + '\", ' }}\n", 117 " {{- '\"description\": \"' + tool.name + '(' }}\n", 118 " {%- for param_name, param_fields in tool.parameters.properties|items %}\n", 119 " {{- param_name + \": \" + json_to_python_type(param_fields) }}\n", 120 " {%- if not loop.last %}\n", 121 " {{- \", \" }}\n", 122 " {%- endif %}\n", 123 " {%- endfor %}\n", 124 " {{- \")\" }}\n", 125 " {%- if tool.return is defined %}\n", 126 " {{- \" -> \" + json_to_python_type(tool.return) }}\n", 127 " {%- endif %}\n", 128 " {{- \" - \" + tool.description + \"\\n\\n\" }}\n", 129 " {%- for param_name, param_fields in tool.parameters.properties|items %}\n", 130 " {%- if loop.first %}\n", 131 " {{- \" Args:\\n\" }}\n", 132 " {%- endif %}\n", 133 " {{- \" \" + param_name + \"(\" + json_to_python_type(param_fields) + \"): \" + param_fields.description|trim }}\n", 134 " {%- endfor %}\n", 135 " {%- if tool.return is defined and tool.return.description is defined %}\n", 136 " {{- \"\\n Returns:\\n \" + tool.return.description }}\n", 137 " {%- endif %}\n", 138 " {{- '\"' }}\n", 139 " {{- ', \"parameters\": ' }}\n", 140 " {%- if tool.parameters.properties | length == 0 %}\n", 141 " {{- \"{}\" }}\n", 142 " {%- else %}\n", 143 " {{- tool.parameters|tojson }}\n", 144 " {%- endif %}\n", 145 " {{- \"}\" }}\n", 146 " {%- if not loop.last %}\n", 147 " {{- \"\\n\" }}\n", 148 " {%- endif %}\n", 149 "{%- endfor %}\n", 150 "{{- \" </tools>\" }}\n", 151 "{{- 'Use the following pydantic model json schema for each tool call you will make: {\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"arguments\": {\"title\": \"Arguments\", \"type\": \"object\"}}, \"required\": [\"name\", \"arguments\"], \"title\": \"FunctionCall\", \"type\": \"object\"}}\n", 152 "' }}\n", 153 "{{- \"For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:\n", 154 "\" }}\n", 155 "{{- \"<tool_call>\n", 156 "\" }}\n", 157 "{{- '{\"name\": <function-name>, \"arguments\": <args-dict>}\n", 158 "' }}\n", 159 "{{- '</tool_call><|im_end|>\\n' }}\n", 160 "{%- for message in messages %}\n", 161 " {%- if message.role == \"user\" or message.role == \"system\" or (message.role == \"assistant\" and message.tool_calls is not defined) %}\n", 162 " {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n", 163 " {%- elif message.role == \"assistant\" %}\n", 164 " {{- '<|im_start|>' + message.role }}\n", 165 " {%- for tool_call in message.tool_calls %}\n", 166 " {{- '\n", 167 "<tool_call>\n", 168 "' }} {%- if tool_call.function is defined %}\n", 169 " {%- set tool_call = tool_call.function %}\n", 170 " {%- endif %}\n", 171 " {{- '{' }}\n", 172 " {{- '\"name\": \"' }}\n", 173 " {{- tool_call.name }}\n", 174 " {{- '\"' }}\n", 175 " {{- ', '}}\n", 176 " {%- if tool_call.arguments is defined %}\n", 177 " {{- '\"arguments\": ' }}\n", 178 " {%- if tool_call.arguments is string %}\n", 179 " {{- tool_call.arguments }}\n", 180 " {%- else %}\n", 181 " {{- tool_call.arguments|tojson }}\n", 182 " {%- endif %}\n", 183 " {%- endif %}\n", 184 " {{- '}' }}\n", 185 " {{- '\\n</tool_call>' }}\n", 186 " {%- endfor %}\n", 187 " {{- '<|im_end|>\\n' }}\n", 188 " {%- elif message.role == \"tool\" %}\n", 189 " {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n", 190 " {{- '<|im_start|>tool\\n' }}\n", 191 " {%- endif %}\n", 192 " {{- '<tool_response>\\n' }}\n", 193 " {{- message.content }}\n", 194 " {%- if not loop.last %}\n", 195 " {{- '\\n</tool_response>\\n' }}\n", 196 " {%- else %}\n", 197 " {{- '\\n</tool_response>' }}\n", 198 " {%- endif %}\n", 199 " {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n", 200 " {{- '<|im_end|>' }}\n", 201 " {%- elif loop.last %}\n", 202 " {{- '<|im_end|>' }}\n", 203 " {%- endif %}\n", 204 " {%- endif %}\n", 205 "{%- endfor %}\n", 206 "{%- if add_generation_prompt %}\n", 207 " {{- '<|im_start|>assistant\\n' }}\n", 208 "{%- endif %}\n", 209 "\"\"\"" 210 ] 211 }, 212 { 213 "cell_type": "code", 214 "execution_count": 5, 215 "metadata": {}, 216 "outputs": [ 217 { 218 "name": "stdout", 219 "output_type": "stream", 220 "text": [ 221 "\"template\": \"{%- macro json_to_python_type(json_spec) %}\\n{%- set basic_type_map = {\\n \\\"string\\\": \\\"str\\\",\\n \\\"number\\\": \\\"float\\\",\\n \\\"integer\\\": \\\"int\\\",\\n \\\"boolean\\\": \\\"bool\\\"\\n} %}\\n\\n{%- if basic_type_map[json_spec.type] is defined %}\\n {{- basic_type_map[json_spec.type] }}\\n{%- elif json_spec.type == \\\"array\\\" %}\\n {{- \\\"list[\\\" + json_to_python_type(json_spec|items) + \\\"]\\\"}}\\n{%- elif json_spec.type == \\\"object\\\" %}\\n {%- if json_spec.additionalProperties is defined %}\\n {{- \\\"dict[str, \\\" + json_to_python_type(json_spec.additionalProperties) + ']'}}\\n {%- else %}\\n {{- \\\"dict\\\" }}\\n {%- endif %}\\n{%- elif json_spec.type is iterable %}\\n {{- \\\"Union[\\\" }}\\n {%- for t in json_spec.type %}\\n {{- json_to_python_type({\\\"type\\\": t}) }}\\n {%- if not loop.last %}\\n {{- \\\",\\\" }} \\n {%- endif %}\\n {%- endfor %}\\n {{- \\\"]\\\" }}\\n{%- else %}\\n {{- \\\"Any\\\" }}\\n{%- endif %}\\n{%- endmacro %}\\n\\n\\n{{- bos_token }}\\n{{- '<|im_start|>system\\n' }}\\n{{- \\\"You are a function calling AI model. You are provided with function signatures within <tools></tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: <tools> \\\" }}\\n{%- for tool in tools %}\\n {%- if tool.function is defined %}\\n {%- set tool = tool.function %}\\n {%- endif %}\\n {{- '{\\\"type\\\": \\\"function\\\", \\\"function\\\": ' }}\\n {{- '{\\\"name\\\": \\\"' + tool.name + '\\\", ' }}\\n {{- '\\\"description\\\": \\\"' + tool.name + '(' }}\\n {%- for param_name, param_fields in tool.parameters.properties|items %}\\n {{- param_name + \\\": \\\" + json_to_python_type(param_fields) }}\\n {%- if not loop.last %}\\n {{- \\\", \\\" }}\\n {%- endif %}\\n {%- endfor %}\\n {{- \\\")\\\" }}\\n {%- if tool.return is defined %}\\n {{- \\\" -> \\\" + json_to_python_type(tool.return) }}\\n {%- endif %}\\n {{- \\\" - \\\" + tool.description + \\\"\\n\\n\\\" }}\\n {%- for param_name, param_fields in tool.parameters.properties|items %}\\n {%- if loop.first %}\\n {{- \\\" Args:\\n\\\" }}\\n {%- endif %}\\n {{- \\\" \\\" + param_name + \\\"(\\\" + json_to_python_type(param_fields) + \\\"): \\\" + param_fields.description|trim }}\\n {%- endfor %}\\n {%- if tool.return is defined and tool.return.description is defined %}\\n {{- \\\"\\n Returns:\\n \\\" + tool.return.description }}\\n {%- endif %}\\n {{- '\\\"' }}\\n {{- ', \\\"parameters\\\": ' }}\\n {%- if tool.parameters.properties | length == 0 %}\\n {{- \\\"{}\\\" }}\\n {%- else %}\\n {{- tool.parameters|tojson }}\\n {%- endif %}\\n {{- \\\"}\\\" }}\\n {%- if not loop.last %}\\n {{- \\\"\\n\\\" }}\\n {%- endif %}\\n{%- endfor %}\\n{{- \\\" </tools>\\\" }}\\n{{- 'Use the following pydantic model json schema for each tool call you will make: {\\\"properties\\\": {\\\"name\\\": {\\\"title\\\": \\\"Name\\\", \\\"type\\\": \\\"string\\\"}, \\\"arguments\\\": {\\\"title\\\": \\\"Arguments\\\", \\\"type\\\": \\\"object\\\"}}, \\\"required\\\": [\\\"name\\\", \\\"arguments\\\"], \\\"title\\\": \\\"FunctionCall\\\", \\\"type\\\": \\\"object\\\"}}\\n' }}\\n{{- \\\"For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:\\n\\\" }}\\n{{- \\\"<tool_call>\\n\\\" }}\\n{{- '{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-dict>}\\n' }}\\n{{- '</tool_call><|im_end|>\\n' }}\\n{%- for message in messages %}\\n {%- if message.role == \\\"user\\\" or message.role == \\\"system\\\" or (message.role == \\\"assistant\\\" and message.tool_calls is not defined) %}\\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\\n {%- elif message.role == \\\"assistant\\\" %}\\n {{- '<|im_start|>' + message.role }}\\n {%- for tool_call in message.tool_calls %}\\n {{- '\\n<tool_call>\\n' }} {%- if tool_call.function is defined %}\\n {%- set tool_call = tool_call.function %}\\n {%- endif %}\\n {{- '{' }}\\n {{- '\\\"name\\\": \\\"' }}\\n {{- tool_call.name }}\\n {{- '\\\"' }}\\n {{- ', '}}\\n {%- if tool_call.arguments is defined %}\\n {{- '\\\"arguments\\\": ' }}\\n {%- if tool_call.arguments is string %}\\n {{- tool_call.arguments }}\\n {%- else %}\\n {{- tool_call.arguments|tojson }}\\n {%- endif %}\\n {%- endif %}\\n {{- '\\n</tool_call>' }}\\n {%- endfor %}\\n {{- '<|im_end|>\\n' }}\\n {%- elif message.role == \\\"tool\\\" %}\\n {%- if loop.previtem and loop.previtem.role != \\\"tool\\\" %}\\n {{- '<|im_start|>tool\\n' }}\\n {%- endif %}\\n {{- '<tool_response>\\n' }}\\n {{- message.content }}\\n {%- if not loop.last %}\\n {{- '\\n</tool_response>\\n' }}\\n {%- else %}\\n {{- '\\n</tool_response>' }}\\n {%- endif %}\\n {%- if not loop.last and loop.nextitem.role != \\\"tool\\\" %}\\n {{- '<|im_end|>' }}\\n {%- elif loop.last %}\\n {{- '<|im_end|>' }}\\n {%- endif %}\\n {%- endif %}\\n{%- endfor %}\\n{%- if add_generation_prompt %}\\n {{- '<|im_start|>assistant\\n' }}\\n{%- endif %}\\n\"\n" 222 ] 223 } 224 ], 225 "source": [ 226 "import json\n", 227 "\n", 228 "# Assuming template_str is your original multi-line string\n", 229 "escaped_template = json.dumps(template_str)\n", 230 "\n", 231 "# Create the final formatted string\n", 232 "formatted_template = f'\"template\": {escaped_template}'\n", 233 "\n", 234 "print(formatted_template)" 235 ] 236 }, 237 { 238 "cell_type": "code", 239 "execution_count": 6, 240 "metadata": {}, 241 "outputs": [ 242 { 243 "name": "stdout", 244 "output_type": "stream", 245 "text": [ 246 "{%- macro json_to_python_type(json_spec) %}\n", 247 "{%- set basic_type_map = {\n", 248 " \"string\": \"str\",\n", 249 " \"number\": \"float\",\n", 250 " \"integer\": \"int\",\n", 251 " \"boolean\": \"bool\"\n", 252 "} %}\n", 253 "\n", 254 "{%- if basic_type_map[json_spec.type] is defined %}\n", 255 " {{- basic_type_map[json_spec.type] }}\n", 256 "{%- elif json_spec.type == \"array\" %}\n", 257 " {{- \"list[\" + json_to_python_type(json_spec|items) + \"]\"}}\n", 258 "{%- elif json_spec.type == \"object\" %}\n", 259 " {%- if json_spec.additionalProperties is defined %}\n", 260 " {{- \"dict[str, \" + json_to_python_type(json_spec.additionalProperties) + ']'}}\n", 261 " {%- else %}\n", 262 " {{- \"dict\" }}\n", 263 " {%- endif %}\n", 264 "{%- elif json_spec.type is iterable %}\n", 265 " {{- \"Union[\" }}\n", 266 " {%- for t in json_spec.type %}\n", 267 " {{- json_to_python_type({\"type\": t}) }}\n", 268 " {%- if not loop.last %}\n", 269 " {{- \",\" }} \n", 270 " {%- endif %}\n", 271 " {%- endfor %}\n", 272 " {{- \"]\" }}\n", 273 "{%- else %}\n", 274 " {{- \"Any\" }}\n", 275 "{%- endif %}\n", 276 "{%- endmacro %}\n", 277 "\n", 278 "\n", 279 "{{- bos_token }}\n", 280 "{{- '<|im_start|>system\n", 281 "' }}\n", 282 "{{- \"You are a function calling AI model. You are provided with function signatures within <tools></tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: <tools> \" }}\n", 283 "{%- for tool in tools %}\n", 284 " {%- if tool.function is defined %}\n", 285 " {%- set tool = tool.function %}\n", 286 " {%- endif %}\n", 287 " {{- '{\"type\": \"function\", \"function\": ' }}\n", 288 " {{- '{\"name\": \"' + tool.name + '\", ' }}\n", 289 " {{- '\"description\": \"' + tool.name + '(' }}\n", 290 " {%- for param_name, param_fields in tool.parameters.properties|items %}\n", 291 " {{- param_name + \": \" + json_to_python_type(param_fields) }}\n", 292 " {%- if not loop.last %}\n", 293 " {{- \", \" }}\n", 294 " {%- endif %}\n", 295 " {%- endfor %}\n", 296 " {{- \")\" }}\n", 297 " {%- if tool.return is defined %}\n", 298 " {{- \" -> \" + json_to_python_type(tool.return) }}\n", 299 " {%- endif %}\n", 300 " {{- \" - \" + tool.description + \"\n", 301 "\n", 302 "\" }}\n", 303 " {%- for param_name, param_fields in tool.parameters.properties|items %}\n", 304 " {%- if loop.first %}\n", 305 " {{- \" Args:\n", 306 "\" }}\n", 307 " {%- endif %}\n", 308 " {{- \" \" + param_name + \"(\" + json_to_python_type(param_fields) + \"): \" + param_fields.description|trim }}\n", 309 " {%- endfor %}\n", 310 " {%- if tool.return is defined and tool.return.description is defined %}\n", 311 " {{- \"\n", 312 " Returns:\n", 313 " \" + tool.return.description }}\n", 314 " {%- endif %}\n", 315 " {{- '\"' }}\n", 316 " {{- ', \"parameters\": ' }}\n", 317 " {%- if tool.parameters.properties | length == 0 %}\n", 318 " {{- \"{}\" }}\n", 319 " {%- else %}\n", 320 " {{- tool.parameters|tojson }}\n", 321 " {%- endif %}\n", 322 " {{- \"}\" }}\n", 323 " {%- if not loop.last %}\n", 324 " {{- \"\n", 325 "\" }}\n", 326 " {%- endif %}\n", 327 "{%- endfor %}\n", 328 "{{- \" </tools>\" }}\n", 329 "{{- 'Use the following pydantic model json schema for each tool call you will make: {\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"arguments\": {\"title\": \"Arguments\", \"type\": \"object\"}}, \"required\": [\"name\", \"arguments\"], \"title\": \"FunctionCall\", \"type\": \"object\"}}\n", 330 "' }}\n", 331 "{{- \"For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:\n", 332 "\" }}\n", 333 "{{- \"<tool_call>\n", 334 "\" }}\n", 335 "{{- '{\"name\": <function-name>, \"arguments\": <args-dict>}\n", 336 "' }}\n", 337 "{{- '</tool_call><|im_end|>\n", 338 "' }}\n", 339 "{%- for message in messages %}\n", 340 " {%- if message.role == \"user\" or message.role == \"system\" or (message.role == \"assistant\" and message.tool_calls is not defined) %}\n", 341 " {{- '<|im_start|>' + message.role + '\n", 342 "' + message.content + '<|im_end|>' + '\n", 343 "' }}\n", 344 " {%- elif message.role == \"assistant\" %}\n", 345 " {{- '<|im_start|>' + message.role }}\n", 346 " {%- for tool_call in message.tool_calls %}\n", 347 " {{- '\n", 348 "<tool_call>\n", 349 "' }} {%- if tool_call.function is defined %}\n", 350 " {%- set tool_call = tool_call.function %}\n", 351 " {%- endif %}\n", 352 " {{- '{' }}\n", 353 " {{- '\"name\": \"' }}\n", 354 " {{- tool_call.name }}\n", 355 " {{- '\"' }}\n", 356 " {{- ', '}}\n", 357 " {%- if tool_call.arguments is defined %}\n", 358 " {{- '\"arguments\": ' }}\n", 359 " {%- if tool_call.arguments is string %}\n", 360 " {{- tool_call.arguments }}\n", 361 " {%- else %}\n", 362 " {{- tool_call.arguments|tojson }}\n", 363 " {%- endif %}\n", 364 " {%- endif %}\n", 365 " {{- '\n", 366 "</tool_call>' }}\n", 367 " {%- endfor %}\n", 368 " {{- '<|im_end|>\n", 369 "' }}\n", 370 " {%- elif message.role == \"tool\" %}\n", 371 " {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n", 372 " {{- '<|im_start|>tool\n", 373 "' }}\n", 374 " {%- endif %}\n", 375 " {{- '<tool_response>\n", 376 "' }}\n", 377 " {{- message.content }}\n", 378 " {%- if not loop.last %}\n", 379 " {{- '\n", 380 "</tool_response>\n", 381 "' }}\n", 382 " {%- else %}\n", 383 " {{- '\n", 384 "</tool_response>' }}\n", 385 " {%- endif %}\n", 386 " {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n", 387 " {{- '<|im_end|>' }}\n", 388 " {%- elif loop.last %}\n", 389 " {{- '<|im_end|>' }}\n", 390 " {%- endif %}\n", 391 " {%- endif %}\n", 392 "{%- endfor %}\n", 393 "{%- if add_generation_prompt %}\n", 394 " {{- '<|im_start|>assistant\n", 395 "' }}\n", 396 "{%- endif %}\n", 397 "\n" 398 ] 399 } 400 ], 401 "source": [ 402 "print(tokenizer.chat_template[\"tool_use\"])" 403 ] 404 }, 405 { 406 "cell_type": "code", 407 "execution_count": 7, 408 "metadata": {}, 409 "outputs": [ 410 { 411 "name": "stdout", 412 "output_type": "stream", 413 "text": [ 414 "<|im_start|>system\n", 415 "You are a function calling AI model. You are provided with function signatures within <tools></tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions. Here are the available tools: <tools> </tools>Use the following pydantic model json schema for each tool call you will make: {\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"arguments\": {\"title\": \"Arguments\", \"type\": \"object\"}}, \"required\": [\"name\", \"arguments\"], \"title\": \"FunctionCall\", \"type\": \"object\"}}\n", 416 "For each function call return a json object with function name and arguments within <tool_call></tool_call> XML tags as follows:\n", 417 "<tool_call>\n", 418 "{\"name\": <function-name>, \"arguments\": <args-dict>}\n", 419 "</tool_call><|im_end|>\n", 420 "<|im_start|>user\n", 421 "Get the current weather forecast for Paris and get stock price of Hermes International<|im_end|>\n", 422 "<|im_start|>assistant\n", 423 "<tool_call>\n", 424 "{\"name\": \"get_weather_forecast\", \"arguments\": {\"location\": \"Paris\"}\n", 425 "</tool_call>\n", 426 "<tool_call>\n", 427 "{\"name\": \"get_stock_price\", \"arguments\": {\"symbol\": \"RMS.PA\"}\n", 428 "</tool_call><|im_end|>\n", 429 "<|im_start|>tool\n", 430 "<tool_response>\n", 431 "{\"name\": \"get_weather_forecast\", \"content\": {\"location\": \"Paris\", \"forecast\": \"Sunny\", \"temperature\": \"+84\\u00b0F\"}}\n", 432 "</tool_response>\n", 433 "<tool_response>\n", 434 "{\"name\": \"get_stock_price\", \"content\": \"Unable to fetch stock price for RMS.PA. Response: {'Global Quote': {}}\"}\n", 435 "</tool_response><|im_end|>\n" 436 ] 437 } 438 ], 439 "source": [ 440 "from jinja2 import Template\n", 441 "# The message array\n", 442 "messages = [\n", 443 " {\n", 444 " \"role\": \"user\",\n", 445 " \"content\": \"Get the current weather forecast for Paris and get stock price of Hermes International\"\n", 446 " },\n", 447 " {\n", 448 " \"role\": \"assistant\",\n", 449 " \"tool_calls\": [\n", 450 " {\n", 451 " \"type\": \"function\",\n", 452 " \"function\": {\n", 453 " \"name\": \"get_weather_forecast\",\n", 454 " \"arguments\": \"{\\\"location\\\": \\\"Paris\\\"}\"\n", 455 " }\n", 456 " },\n", 457 " {\n", 458 " \"type\": \"function\",\n", 459 " \"function\": {\n", 460 " \"name\": \"get_stock_price\",\n", 461 " \"arguments\": \"{\\\"symbol\\\": \\\"RMS.PA\\\"}\"\n", 462 " }\n", 463 " }\n", 464 " ]\n", 465 " },\n", 466 " {\n", 467 " \"role\": \"tool\",\n", 468 " \"content\": \"{\\\"name\\\": \\\"get_weather_forecast\\\", \\\"content\\\": {\\\"location\\\": \\\"Paris\\\", \\\"forecast\\\": \\\"Sunny\\\", \\\"temperature\\\": \\\"+84\\\\u00b0F\\\"}}\",\n", 469 " #\"tool_call_id\": \"call_62136354\"\n", 470 " #\"name\": \"get_weather_forecast\"\n", 471 " },\n", 472 " {\n", 473 " \"role\": \"tool\",\n", 474 " \"content\": \"{\\\"name\\\": \\\"get_stock_price\\\", \\\"content\\\": \\\"Unable to fetch stock price for RMS.PA. Response: {'Global Quote': {}}\\\"}\",\n", 475 " #\"tool_call_id\": \"call_62136355\"\n", 476 " #\"name\": \"get_stock_price\"\n", 477 " }\n", 478 "]\n", 479 "\n", 480 "# Create the Jinja2 template\n", 481 "template = Template(template_str)\n", 482 "#template = Template(tokenizer.chat_template[\"tool_use\"])\n", 483 "\n", 484 "# Render the template\n", 485 "result = template.render(messages=messages)\n", 486 "\n", 487 "# Print the result\n", 488 "print(result)" 489 ] 490 }, 491 { 492 "cell_type": "code", 493 "execution_count": 8, 494 "metadata": {}, 495 "outputs": [], 496 "source": [ 497 "def parse_tool_calls(text):\n", 498 " pattern = r'<tool_call>\\s*(.*?)\\s*</tool_call>'\n", 499 " matches = re.findall(pattern, text, re.DOTALL)\n", 500 " \n", 501 " function_calls = []\n", 502 " for match in matches:\n", 503 " print(f\"Raw match: {match}\") # Print raw match\n", 504 " try:\n", 505 " # Remove newlines and extra whitespace\n", 506 " cleaned_match = re.sub(r'\\s+', ' ', match).strip()\n", 507 " print(f\"Cleaned match: {cleaned_match}\") # Print cleaned match\n", 508 " \n", 509 " data = json.loads(cleaned_match)\n", 510 " print(f\"Parsed JSON: {data}\") # Print parsed JSON\n", 511 " \n", 512 " # Parse the arguments string into a dictionary\n", 513 " if isinstance(data['arguments'], str):\n", 514 " data['arguments'] = json.loads(data['arguments'])\n", 515 " \n", 516 " function_call = FunctionCall(**data)\n", 517 " function_calls.append(function_call)\n", 518 " print(f\"Validated function call: {function_call}\") # Print validated function call\n", 519 " except json.JSONDecodeError as e:\n", 520 " print(f\"Error parsing JSON: {e}\")\n", 521 " except ValueError as e:\n", 522 " print(f\"Error validating data: {e}\")\n", 523 " \n", 524 " return function_calls\n" 525 ] 526 }, 527 { 528 "cell_type": "code", 529 "execution_count": 9, 530 "metadata": {}, 531 "outputs": [ 532 { 533 "name": "stdout", 534 "output_type": "stream", 535 "text": [ 536 "Raw match: {\"name\": \"get_weather_forecast\", \"arguments\": {\"location\": \"Paris\"}\n", 537 "Cleaned match: {\"name\": \"get_weather_forecast\", \"arguments\": {\"location\": \"Paris\"}\n", 538 "Error parsing JSON: Expecting ',' delimiter: line 1 column 68 (char 67)\n", 539 "Raw match: {\"name\": \"get_stock_price\", \"arguments\": {\"symbol\": \"RMS.PA\"}\n", 540 "Cleaned match: {\"name\": \"get_stock_price\", \"arguments\": {\"symbol\": \"RMS.PA\"}\n", 541 "Error parsing JSON: Expecting ',' delimiter: line 1 column 62 (char 61)\n", 542 "\n", 543 "Final result:\n" 544 ] 545 } 546 ], 547 "source": [ 548 "# Test the updated function\n", 549 "result = parse_tool_calls(\"\"\"\n", 550 "<|im_start|>assistant\n", 551 "<tool_call>\n", 552 "{\"name\": \"get_weather_forecast\", \"arguments\": {\"location\": \"Paris\"}\n", 553 "</tool_call>\n", 554 "<tool_call>\n", 555 "{\"name\": \"get_stock_price\", \"arguments\": {\"symbol\": \"RMS.PA\"}\n", 556 "</tool_call><|im_end|>\n", 557 "\"\"\")\n", 558 "\n", 559 "print(\"\\nFinal result:\")\n", 560 "for call in result:\n", 561 " print(call)" 562 ] 563 }, 564 { 565 "cell_type": "code", 566 "execution_count": null, 567 "metadata": {}, 568 "outputs": [], 569 "source": [] 570 } 571 ], 572 "metadata": { 573 "kernelspec": { 574 "display_name": "hermes-tools", 575 "language": "python", 576 "name": "python3" 577 }, 578 "language_info": { 579 "codemirror_mode": { 580 "name": "ipython", 581 "version": 3 582 }, 583 "file_extension": ".py", 584 "mimetype": "text/x-python", 585 "name": "python", 586 "nbconvert_exporter": "python", 587 "pygments_lexer": "ipython3", 588 "version": "3.11.0" 589 } 590 }, 591 "nbformat": 4, 592 "nbformat_minor": 2 593 }