| 
 | 1 | +{%- macro is_array_of_type_objects(var) -%}  | 
 | 2 | +    {%- if var is iterable and var is not string -%}  | 
 | 3 | +        {%- set valid = true -%}  | 
 | 4 | +        {%- for item in var -%}  | 
 | 5 | +            {%- if 'type' not in item -%}  | 
 | 6 | +                {%- set valid = false -%}  | 
 | 7 | +                {%- break -%}  | 
 | 8 | +            {%- endif -%}  | 
 | 9 | +        {%- endfor -%}  | 
 | 10 | +        {{ valid }}  | 
 | 11 | +    {%- else -%}  | 
 | 12 | +        {{ false }}  | 
 | 13 | +    {%- endif -%}  | 
 | 14 | +{%- endmacro %}  | 
 | 15 | + | 
 | 16 | +{%- macro render_message(message) %}  | 
 | 17 | +    {%- if message['content'] is string %}  | 
 | 18 | +        {{- message['content']|trim }}  | 
 | 19 | +    {%- elif is_array_of_type_objects(data) == 'True' %}  | 
 | 20 | +        {%- for content in message['content'] %}  | 
 | 21 | +            {%- if content['type'] == 'image' %}  | 
 | 22 | +                {{- '<|image|>' }}  | 
 | 23 | +            {%- elif content['type'] == 'text' %}  | 
 | 24 | +                {{- content['text']|trim }}  | 
 | 25 | +            {%- endif %}  | 
 | 26 | +        {%- endfor %}  | 
 | 27 | +    {%- else %}  | 
 | 28 | +        {{- message['content']|tojson }}  | 
 | 29 | +    {%- endif %}  | 
 | 30 | +{%- endmacro %}  | 
 | 31 | + | 
 | 32 | +{{- bos_token }}  | 
 | 33 | +{%- if custom_tools is defined %}  | 
 | 34 | +    {%- set tools = custom_tools %}  | 
 | 35 | +{%- endif %}  | 
 | 36 | +{%- if not tools_in_user_message is defined %}  | 
 | 37 | +    {%- set tools_in_user_message = true %}  | 
 | 38 | +{%- endif %}  | 
 | 39 | +{%- if not tools is defined %}  | 
 | 40 | +    {%- set tools = none %}  | 
 | 41 | +{%- endif %}  | 
 | 42 | + | 
 | 43 | +{#- This block extracts the system message, so we can slot it into the right place. #}  | 
 | 44 | +{%- if messages[0]['role'] == 'system' %}  | 
 | 45 | +    {%- set system_message = messages[0] %}  | 
 | 46 | +    {%- set messages = messages[1:] %}  | 
 | 47 | +{%- else %}  | 
 | 48 | +    {%- set system_message = ({ "content": "You are a helpful assistant with tool calling "  | 
 | 49 | +        "capabilities. Only reply with a tool call if the function exists in the "  | 
 | 50 | +        "library provided by the user. If it doesn't exist, just reply directly in "  | 
 | 51 | +        "natural language. When you receive a tool call response, use the output to "  | 
 | 52 | +        "format an answer to the original user question."}) %}  | 
 | 53 | +{%- endif %}  | 
 | 54 | + | 
 | 55 | +{%- set tool_lib_preamble = 'Tools: You have access to the following tools. You might need to use one '  | 
 | 56 | +    'or more function/tool calls to fulfill the task. \n'  | 
 | 57 | +    'If none are needed, then proceed to the response.\n\n'  | 
 | 58 | +    'Tool Call Syntax: You can call tools using the following syntax:\n'  | 
 | 59 | +    '{"name": function name, "parameters": dictionary of argument name and its value}.\n'  | 
 | 60 | +    'Separate multiple function calls by "; ". Do not use variables.\n'  | 
 | 61 | +    'Do not include anything else when calling the tools with the syntax above.\n\n'  | 
 | 62 | +    'Here is a list of functions in JSON format that you can invoke.\n' %}  | 
 | 63 | + | 
 | 64 | +{{- "<|header_start|>system<|header_end|>\n\n" }}  | 
 | 65 | +{%- if tools is not none and not tools_in_user_message %}  | 
 | 66 | +    {{- tool_lib_preamble }}  | 
 | 67 | +    {%- for t in tools %}  | 
 | 68 | +        {{- t | tojson(indent=4) }}  | 
 | 69 | +        {{- "\n\n" }}  | 
 | 70 | +    {%- endfor %}  | 
 | 71 | +{%- endif %}  | 
 | 72 | +{{- render_message(system_message) }}  | 
 | 73 | +{{ "<|eot|>\n" }}  | 
 | 74 | + | 
 | 75 | +{#- Custom tools are passed in a user message with some extra guidance #}  | 
 | 76 | +{%- if tools_in_user_message and not tools is none %}  | 
 | 77 | +    {#- Extract the first user message so we can plug it in here #}  | 
 | 78 | +    {%- if messages | length != 0 %}  | 
 | 79 | +        {%- set first_user_message = messages[0] %}  | 
 | 80 | +        {%- set messages = messages[1:] %}  | 
 | 81 | +    {%- else %}  | 
 | 82 | +        {{- raise_exception("Cannot put tools in the first user message when there's no first user message!") }}  | 
 | 83 | +    {%- endif %}  | 
 | 84 | +    {{- '<|header_start|>user<|header_end|>\n\n' }}  | 
 | 85 | +    {{- tool_lib_preamble }}  | 
 | 86 | +    {%- for t in tools %}  | 
 | 87 | +        {{- t | tojson(indent=4) }}  | 
 | 88 | +        {{- "\n\n" }}  | 
 | 89 | +    {%- endfor %}  | 
 | 90 | +    {{- render_message(first_user_message) + "\n<|eot|>"}}  | 
 | 91 | +{%- endif %}  | 
 | 92 | + | 
 | 93 | +{%- for message in messages %}  | 
 | 94 | +    {%- if not (message.role == 'ipython' or message.role == 'tool' or 'tool_calls' in message) %}  | 
 | 95 | +        {{- '<|header_start|>' + message['role'] + '<|header_end|>\n\n' }}  | 
 | 96 | +        {{- render_message(message) }}  | 
 | 97 | +        {{- "\n<|eot|>" }}  | 
 | 98 | +    {%- elif 'tool_calls' in message and message.tool_calls|length > 0 %}  | 
 | 99 | +        {{- '\n<|header_start|>assistant<|header_end|>\n\n' -}}  | 
 | 100 | +        {{- render_message(message) }}  | 
 | 101 | +        {%- for tool_call in message.tool_calls %}  | 
 | 102 | +           {{- '{"name": "' + tool_call.function.name + '", ' }}  | 
 | 103 | +           {{- '"parameters": ' }}  | 
 | 104 | +           {{- tool_call.function.arguments | tojson }}  | 
 | 105 | +           {{- "}" }}  | 
 | 106 | +        {%- endfor %}  | 
 | 107 | +       {{- "\n<|eot|>" }}  | 
 | 108 | +    {%- elif message.role == "tool" or message.role == "ipython" %}  | 
 | 109 | +        {{- "\n<|header_start|>ipython<|header_end|>\n\n" }}  | 
 | 110 | +        {{- render_message(message) }}  | 
 | 111 | +        {{- "\n<|eom|>" }}  | 
 | 112 | +    {%- endif %}  | 
 | 113 | +{%- endfor %}  | 
 | 114 | +{%- if add_generation_prompt %}  | 
 | 115 | +    {{- '\n<|header_start|>assistant<|header_end|>\n\n' }}  | 
 | 116 | +{%- endif %}  | 
0 commit comments