|
1380 | 1380 | {%- set tool = tool.function %} |
1381 | 1381 | {{- "// " + tool.description + "\n" }} |
1382 | 1382 | {{- "type "+ tool.name + " = " }} |
1383 | | - {%- if tool.parameters and tool.parameters.properties -%} |
1384 | | - {{- "(_: " }} |
1385 | | - {{- "{\n" }} |
| 1383 | + {%- if tool.parameters and tool.parameters.properties %} |
| 1384 | + {{- "(_: {\n" }} |
1386 | 1385 | {%- for param_name, param_spec in tool.parameters.properties.items() %} |
1387 | | - {{- "// " + param_spec.description + "\n" }} |
| 1386 | + {%- if param_spec.description %} |
| 1387 | + {{- "// " + param_spec.description + "\n" }} |
| 1388 | + {%- endif %} |
1388 | 1389 | {{- param_name }} |
1389 | 1390 | {%- if param_name not in (tool.parameters.required or []) -%} |
1390 | 1391 | {{- "?" }} |
|
1403 | 1404 | {%- if not loop.last %} |
1404 | 1405 | {{- ",\n" }} |
1405 | 1406 | {%- else %} |
1406 | | - {{- "\n" }} |
| 1407 | + {{- ",\n" }} |
1407 | 1408 | {%- endif -%} |
1408 | 1409 | {%- endfor %} |
1409 | 1410 | {{- "}) => any;\n\n" }} |
|
1462 | 1463 | {#- System Message Construction ============================================ #} |
1463 | 1464 | {%- macro build_system_message() -%} |
1464 | 1465 | {%- if model_identity is not defined %} |
1465 | | - {{- "You are ChatGPT, a large language model trained by OpenAI.\n" -}} |
1466 | | - {%- else %} |
1467 | | - {{- model_identity }} |
| 1466 | + {%- set model_identity = "You are ChatGPT, a large language model trained by OpenAI." %} |
1468 | 1467 | {%- endif %} |
| 1468 | + {{- model_identity + "\n" }} |
1469 | 1469 | {{- "Knowledge cutoff: 2024-06\n" }} |
1470 | 1470 | {{- "Current date: " + strftime_now("%Y-%m-%d") + "\n\n" }} |
1471 | 1471 | {%- if reasoning_effort is not defined %} |
1472 | 1472 | {%- set reasoning_effort = "medium" %} |
1473 | 1473 | {%- endif %} |
1474 | 1474 | {{- "Reasoning: " + reasoning_effort + "\n\n" }} |
1475 | | - {%- if builtin_tools is defined %} |
| 1475 | + {%- if builtin_tools is defined and builtin_tools is not none %} |
1476 | 1476 | {{- "# Tools\n\n" }} |
1477 | 1477 | {%- set available_builtin_tools = namespace(browser=false, python=false) %} |
1478 | 1478 | {%- for tool in builtin_tools %} |
|
1485 | 1485 | {{- render_builtin_tools(available_builtin_tools.browser, available_builtin_tools.python) }} |
1486 | 1486 | {%- endif -%} |
1487 | 1487 | {{- "# Valid channels: analysis, commentary, final. Channel must be included for every message." }} |
1488 | | - {%- if tools is defined -%} |
| 1488 | + {%- if tools -%} |
1489 | 1489 | {{- "\nCalls to these tools must go to the commentary channel: 'functions'." }} |
1490 | 1490 | {%- endif -%} |
1491 | 1491 | {%- endmacro -%} |
|
1499 | 1499 | {{- "<|end|>" }} |
1500 | 1500 |
|
1501 | 1501 | {#- Extract developer message #} |
1502 | | -{%- if messages[0].role == "developer" or messages[0].role == "system" %} |
| 1502 | +{%- if developer_instructions is defined and developer_instructions is not none %} |
| 1503 | + {%- set developer_message = developer_instructions %} |
| 1504 | + {%- set loop_messages = messages %} |
| 1505 | +{%- elif messages[0].role == "developer" or messages[0].role == "system" %} |
1503 | 1506 | {%- set developer_message = messages[0].content %} |
1504 | 1507 | {%- set loop_messages = messages[1:] %} |
1505 | 1508 | {%- else %} |
|
1515 | 1518 | {{- developer_message }} |
1516 | 1519 | {%- endif %} |
1517 | 1520 | {%- if tools -%} |
1518 | | - {{- "\n\n" }} |
| 1521 | + {%- if developer_message %} |
| 1522 | + {{- "\n\n" }} |
| 1523 | + {%- endif %} |
1519 | 1524 | {{- "# Tools\n\n" }} |
1520 | 1525 | {{- render_tool_namespace("functions", tools) }} |
1521 | 1526 | {%- endif -%} |
|
1527 | 1532 | {%- for message in loop_messages -%} |
1528 | 1533 | {#- At this point only assistant/user/tool messages should remain #} |
1529 | 1534 | {%- if message.role == 'assistant' -%} |
| 1535 | + {#- Checks to ensure the messages are being passed in the format we expect #} |
| 1536 | + {%- if "content" in message %} |
| 1537 | + {%- if "<|channel|>analysis<|message|>" in message.content or "<|channel|>final<|message|>" in message.content %} |
| 1538 | + {{- raise_exception("You have passed a message containing <|channel|> tags in the content field. Instead of doing this, you should pass analysis messages (the string between '<|message|>' and '<|end|>') in the 'thinking' field, and final messages (the string between '<|message|>' and '<|end|>') in the 'content' field.") }} |
| 1539 | + {%- endif %} |
| 1540 | + {%- endif %} |
| 1541 | + {%- if "thinking" in message %} |
| 1542 | + {%- if "<|channel|>analysis<|message|>" in message.thinking or "<|channel|>final<|message|>" in message.thinking %} |
| 1543 | + {{- raise_exception("You have passed a message containing <|channel|> tags in the thinking field. Instead of doing this, you should pass analysis messages (the string between '<|message|>' and '<|end|>') in the 'thinking' field, and final messages (the string between '<|message|>' and '<|end|>') in the 'content' field.") }} |
| 1544 | + {%- endif %} |
| 1545 | + {%- endif %} |
1530 | 1546 | {%- if "tool_calls" in message %} |
| 1547 | + {#- We need very careful handling here - we want to drop the tool call analysis message if the model #} |
| 1548 | + {#- has output a later <|final|> message, but otherwise we want to retain it. This is the only case #} |
| 1549 | + {#- when we render CoT/analysis messages in inference. #} |
| 1550 | + {%- set future_final_message = namespace(found=false) %} |
| 1551 | + {%- for future_message in loop_messages[loop.index:] %} |
| 1552 | + {%- if future_message.role == 'assistant' and "tool_calls" not in future_message %} |
| 1553 | + {%- set future_final_message.found = true %} |
| 1554 | + {%- endif %} |
| 1555 | + {%- endfor %} |
1531 | 1556 | {#- We assume max 1 tool call per message, and so we infer the tool call name #} |
1532 | 1557 | {#- in "tool" messages from the most recent assistant tool call name #} |
1533 | 1558 | {%- set tool_call = message.tool_calls[0] %} |
1534 | 1559 | {%- if tool_call.function %} |
1535 | 1560 | {%- set tool_call = tool_call.function %} |
1536 | 1561 | {%- endif %} |
1537 | | - {%- if message.content %} |
| 1562 | + {%- if message.content and message.thinking %} |
| 1563 | + {{- raise_exception("Cannot pass both content and thinking in an assistant message with tool calls! Put the analysis message in one or the other, but not both.") }} |
| 1564 | + {%- elif message.content and not future_final_message.found %} |
1538 | 1565 | {{- "<|start|>assistant<|channel|>analysis<|message|>" + message.content + "<|end|>" }} |
| 1566 | + {%- elif message.thinking and not future_final_message.found %} |
| 1567 | + {{- "<|start|>assistant<|channel|>analysis<|message|>" + message.thinking + "<|end|>" }} |
1539 | 1568 | {%- endif %} |
1540 | 1569 | {{- "<|start|>assistant to=" }} |
1541 | | - {{- "functions." + tool_call.name + "<|channel|>commentary json<|message|>" }} |
1542 | | - {{- tool_call.arguments|tojson }} |
| 1570 | + {{- "functions." + tool_call.name + "<|channel|>commentary " }} |
| 1571 | + {{- (tool_call.content_type if tool_call.content_type is defined else "json") + "<|message|>" }} |
| 1572 | + {%- if tool_call.arguments is string %} |
| 1573 | + {{- tool_call.arguments }} |
| 1574 | + {%- else %} |
| 1575 | + {{- tool_call.arguments|tojson }} |
| 1576 | + {%- endif %} |
1543 | 1577 | {{- "<|call|>" }} |
1544 | 1578 | {%- set last_tool_call.name = tool_call.name %} |
1545 | | - {%- elif "thinking" in message and loop.last and not add_generation_prompt %} |
| 1579 | + {%- elif loop.last and not add_generation_prompt %} |
1546 | 1580 | {#- Only render the CoT if the final turn is an assistant turn and add_generation_prompt is false #} |
1547 | 1581 | {#- This is a situation that should only occur in training, never in inference. #} |
1548 | | - {{- "<|start|>assistant<|channel|>analysis<|message|>" + message.thinking + "<|end|>" }} |
| 1582 | + {%- if "thinking" in message %} |
| 1583 | + {{- "<|start|>assistant<|channel|>analysis<|message|>" + message.thinking + "<|end|>" }} |
| 1584 | + {%- endif %} |
1549 | 1585 | {#- <|return|> indicates the end of generation, but <|end|> does not #} |
1550 | 1586 | {#- <|return|> should never be an input to the model, but we include it as the final token #} |
1551 | 1587 | {#- when training, so the model learns to emit it. #} |
1552 | | - {{- "<|start|>assistant<|channel|>final<|message|>" + message.content + "<|return|>" }} |
1553 | | - {%- set last_tool_call.name = none %} |
| 1588 | + {{- "<|start|>assistant<|channel|>final<|message|>" + message.content + "<|end|>" }} |
1554 | 1589 | {%- elif "thinking" in message %} |
1555 | 1590 | {#- CoT is dropped during all previous turns, so we never render it for inference #} |
1556 | | - {{- "<|start|>assistant<|channel|>final<|message|>" + message.content + "<|end|>" }} |
| 1591 | + {{- "<|start|>assistant<|channel|>analysis<|message|>" + message.content + "<|end|>" }} |
1557 | 1592 | {%- set last_tool_call.name = none %} |
1558 | | - {%- elif loop.last and not add_generation_prompt %} |
1559 | | - {#- <|return|> indicates the end of generation, but <|end|> does not #} |
1560 | | - {#- <|return|> should never be an input to the model, but we include it as the final token #} |
1561 | | - {#- when training, so the model learns to emit it. #} |
1562 | | - {{- "<|start|>assistant<|message|>" + message.content + "<|return|>" }} |
1563 | 1593 | {%- else %} |
1564 | | - {{- "<|start|>assistant<|message|>" + message.content + "<|end|>" }} |
| 1594 | + {#- CoT is dropped during all previous turns, so we never render it for inference #} |
| 1595 | + {{- "<|start|>assistant<|channel|>final<|message|>" + message.content + "<|end|>" }} |
1565 | 1596 | {%- set last_tool_call.name = none %} |
1566 | 1597 | {%- endif %} |
1567 | 1598 | {%- elif message.role == 'tool' -%} |
1568 | 1599 | {%- if last_tool_call.name is none %} |
1569 | 1600 | {{- raise_exception("Message has tool role, but there was no previous assistant message with a tool call!") }} |
1570 | 1601 | {%- endif %} |
1571 | 1602 | {{- "<|start|>functions." + last_tool_call.name }} |
1572 | | - {{- " to=assistant<|channel|>commentary<|message|>" + message.content|tojson + "<|end|>" }} |
1573 | | - {%- else -%} |
| 1603 | + {%- if message.content is string %} |
| 1604 | + {{- " to=assistant<|channel|>commentary<|message|>" + message.content + "<|end|>" }} |
| 1605 | + {%- else %} |
| 1606 | + {{- " to=assistant<|channel|>commentary<|message|>" + message.content|tojson + "<|end|>" }} |
| 1607 | + {%- endif %} |
| 1608 | + {%- elif message.role == 'user' -%} |
1574 | 1609 | {{- "<|start|>user<|message|>" + message.content + "<|end|>" }} |
1575 | 1610 | {%- endif -%} |
1576 | 1611 | {%- endfor -%} |
|
0 commit comments