/ 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  }