Merge pull request #10513 from mcelrath/dev

Support thinking/solution tags used by Openthinker
This commit is contained in:
Timothy Jaeryang Baek 2025-02-21 10:49:45 -08:00 committed by GitHub
commit b4c64a21b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1127,12 +1127,12 @@ async def process_chat_response(
if reasoning_duration is not None: if reasoning_duration is not None:
if raw: if raw:
content = f'{content}\n<{block["tag"]}>{block["content"]}</{block["tag"]}>\n' content = f'{content}\n<{block["start_tag"]}>{block["content"]}<{block["end_tag"]}>\n'
else: else:
content = f'{content}\n<details type="reasoning" done="true" duration="{reasoning_duration}">\n<summary>Thought for {reasoning_duration} seconds</summary>\n{reasoning_display_content}\n</details>\n' content = f'{content}\n<details type="reasoning" done="true" duration="{reasoning_duration}">\n<summary>Thought for {reasoning_duration} seconds</summary>\n{reasoning_display_content}\n</details>\n'
else: else:
if raw: if raw:
content = f'{content}\n<{block["tag"]}>{block["content"]}</{block["tag"]}>\n' content = f'{content}\n<{block["start_tag"]}>{block["content"]}<{block["end_tag"]}>\n'
else: else:
content = f'{content}\n<details type="reasoning" done="false">\n<summary>Thinking…</summary>\n{reasoning_display_content}\n</details>\n' content = f'{content}\n<details type="reasoning" done="false">\n<summary>Thinking…</summary>\n{reasoning_display_content}\n</details>\n'
@ -1228,9 +1228,9 @@ async def process_chat_response(
return attributes return attributes
if content_blocks[-1]["type"] == "text": if content_blocks[-1]["type"] == "text":
for tag in tags: for start_tag, end_tag in tags:
# Match start tag e.g., <tag> or <tag attr="value"> # Match start tag e.g., <tag> or <tag attr="value">
start_tag_pattern = rf"<{tag}(\s.*?)?>" start_tag_pattern = rf"<{re.escape(start_tag)}(\s.*?)?>"
match = re.search(start_tag_pattern, content) match = re.search(start_tag_pattern, content)
if match: if match:
attr_content = ( attr_content = (
@ -1263,7 +1263,8 @@ async def process_chat_response(
content_blocks.append( content_blocks.append(
{ {
"type": content_type, "type": content_type,
"tag": tag, "start_tag": start_tag,
"end_tag": end_tag,
"attributes": attributes, "attributes": attributes,
"content": "", "content": "",
"started_at": time.time(), "started_at": time.time(),
@ -1275,9 +1276,10 @@ async def process_chat_response(
break break
elif content_blocks[-1]["type"] == content_type: elif content_blocks[-1]["type"] == content_type:
tag = content_blocks[-1]["tag"] start_tag = content_blocks[-1]["start_tag"]
end_tag = content_blocks[-1]["end_tag"]
# Match end tag e.g., </tag> # Match end tag e.g., </tag>
end_tag_pattern = rf"</{tag}>" end_tag_pattern = rf"<{re.escape(end_tag)}>"
# Check if the content has the end tag # Check if the content has the end tag
if re.search(end_tag_pattern, content): if re.search(end_tag_pattern, content):
@ -1285,7 +1287,7 @@ async def process_chat_response(
block_content = content_blocks[-1]["content"] block_content = content_blocks[-1]["content"]
# Strip start and end tags from the content # Strip start and end tags from the content
start_tag_pattern = rf"<{tag}(.*?)>" start_tag_pattern = rf"<{re.escape(start_tag)}(.*?)>"
block_content = re.sub( block_content = re.sub(
start_tag_pattern, "", block_content start_tag_pattern, "", block_content
).strip() ).strip()
@ -1350,7 +1352,7 @@ async def process_chat_response(
# Clean processed content # Clean processed content
content = re.sub( content = re.sub(
rf"<{tag}(.*?)>(.|\n)*?</{tag}>", rf"<{re.escape(start_tag)}(.*?)>(.|\n)*?<{re.escape(end_tag)}>",
"", "",
content, content,
flags=re.DOTALL, flags=re.DOTALL,
@ -1388,19 +1390,28 @@ async def process_chat_response(
# We might want to disable this by default # We might want to disable this by default
DETECT_REASONING = True DETECT_REASONING = True
DETECT_SOLUTION = True
DETECT_CODE_INTERPRETER = metadata.get("features", {}).get( DETECT_CODE_INTERPRETER = metadata.get("features", {}).get(
"code_interpreter", False "code_interpreter", False
) )
reasoning_tags = [ reasoning_tags = [
"think", ("think", "/think"),
"thinking", ("thinking", "/thinking"),
"reason", ("reason", "/reason"),
"reasoning", ("reasoning", "/reasoning"),
"thought", ("thought", "/thought"),
"Thought", ("Thought", "/Thought"),
("|begin_of_thought|", "|end_of_thought|")
]
code_interpreter_tags = [
("code_interpreter", "/code_interpreter")
]
solution_tags = [
("|begin_of_solution|", "|end_of_solution|")
] ]
code_interpreter_tags = ["code_interpreter"]
try: try:
for event in events: for event in events:
@ -1533,6 +1544,16 @@ async def process_chat_response(
if end: if end:
break break
if DETECT_SOLUTION:
content, content_blocks, _ = (
tag_content_handler(
"solution",
solution_tags,
content,
content_blocks,
)
)
if ENABLE_REALTIME_CHAT_SAVE: if ENABLE_REALTIME_CHAT_SAVE:
# Save message in the database # Save message in the database
Chats.upsert_message_to_chat_by_id_and_message_id( Chats.upsert_message_to_chat_by_id_and_message_id(