added support for cohere north mini

This commit is contained in:
Concedo 2026-06-16 00:24:30 +08:00
parent 093067ec01
commit 71801743c4
4 changed files with 55 additions and 19 deletions

View file

@ -3562,7 +3562,7 @@ Current version indicated by LITEVER below.
// whitelisted auto selected horde model names
const defaultmodels = ["gpt4all","supercot","pygmalion-6","pygmalion-v8","pygmalion-2","hermes","airoboros","chrono","wizard","mantis","vicuna","manticore","alpaca","myth","xwin","spicyboros","mlewd","mxlewd","westlake","anubis","skyfall","llama2","llama3","llama-2","llama-3-","llama-3.","mistral","maid","mixtral","estopia","fighter","fimbul","euryale","nemo","gemma","lunaris","stheno","magnum","cydonia","qwen2.5-32b","behemoth","exaone","glm4","glm-4","tutu","deepseek","tlacuilo","rocinante","-14B","-32B","-27B","-35B"];
const ignoredmodels = ["tinyllama","debug-","-1b","-270m"]; //blacklisted model names
const hardcoded_think_closers = ["</think>","<channel|>"];
const hardcoded_think_closers = ["</think>","<channel|>","</seed:think>","<|END_THINKING|>"];
const instructstartplaceholder = "\n{{[INPUT]}}\n";
const instructendplaceholder = "\n{{[OUTPUT]}}\n";

View file

@ -201,7 +201,7 @@
}
}, {
"search": ["<|START_OF_TURN_TOKEN|>"],
"name": "Cohere (Aya Expanse 32B based)",
"name": "Cohere",
"adapter": {
"system_start": "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>",
"system_end": "<|END_OF_TURN_TOKEN|>",
@ -312,6 +312,17 @@
"assistant_end": "\n",
"assistant_gen": "<|begin_assistant|>\nWe can respond now.\n[BEGIN FINAL RESPONSE]\n"
}
}, {
"search": ["<|developer_end|>", "<|assistant_start|>","<|system_start|>"],
"name": "Apertus",
"adapter": {
"system_start": "<|system_start|>",
"system_end": "<|system_end|>",
"user_start": "<|user_start|>",
"user_end": "<|user_end|>",
"assistant_start": "<|assistant_start|>",
"assistant_end": "<|assistant_end|>"
}
}, {
"search": ["[e~[","]~b]user"],
"name": "MiniMax",

View file

@ -194,6 +194,7 @@ tool_call_pairs = [ #third element is optional str to match in chat template bef
("<|end|><|start|>assistant<|channel|>commentary to=", "", None, False), #gpt-oss
("<|tool_call_start|>", "<|tool_call_end|>", "CONTINUE_FINAL_MESSAGE_TAG", True), #lfm2.5
("<tool_calls>", "</tool_calls>", "[BEGIN FINAL RESPONSE]", True), #apriel
("<|START_ACTION|>", "<|END_ACTION|>", "<|START_OF_TURN_TOKEN|>", True), #cohere
]
deprecated_keys = {
"hordeconfig",
@ -3578,21 +3579,47 @@ def toolcall_to_normalized_json(text,start_tag,end_tag,required_match_txt): #con
except Exception:
return text
def parse_cohere2moe(text: str) -> str:
text = text.strip()
try:
calls = json.loads(text)
except Exception:
return text
if isinstance(calls, dict):
calls = [calls]
if not isinstance(calls, list):
return text
results = []
for call in calls:
if not isinstance(call, dict):
continue
fn_name = call.get("tool_name") or call.get("name")
args = call.get("parameters", call.get("arguments", {}))
if not fn_name:
continue
results.append({"name": fn_name,"arguments": args if isinstance(args, dict) else {}})
if not results:
return text
return json.dumps(results) if len(results) > 1 else json.dumps(results[0])
# gemma4 takes precedence, since it can contain valid json fragments
if end_tag=="<tool_call|>":
return parse_gemma4(text)
if start_tag=="<|tool_call_start|>" and end_tag=="<|tool_call_end|>" and cached_chat_template and (required_match_txt is None or required_match_txt in cached_chat_template):
return parse_lfm25(text)
if start_tag=="<|START_ACTION|>" and end_tag=="<|END_ACTION|>" and cached_chat_template and (required_match_txt is None or required_match_txt in cached_chat_template):
return parse_cohere2moe(text)
if start_tag=="<tool_calls>" and end_tag=="</tool_calls>" and cached_chat_template and (required_match_txt is None or required_match_txt in cached_chat_template):
return extract_json_from_string(text, True) #apriel is json
#if we are already valid JSON, return
check_ok = extract_json_from_string(text, True)
if check_ok and len(check_ok)>0:
return text #is valid JSON or parsable
if start_tag=="<|tool_call_start|>" and end_tag=="<|tool_call_end|>" and cached_chat_template and (required_match_txt is None or required_match_txt in cached_chat_template):
return parse_lfm25(text)
if start_tag=="<tool_calls>" and end_tag=="</tool_calls>" and cached_chat_template and (required_match_txt is None or required_match_txt in cached_chat_template):
return extract_json_from_string(text, True) #apriel is json
if "<arg_key>" in text and "<arg_value>" in text: # handle glm with args
return parse_glm(text)
@ -3655,14 +3682,14 @@ def format_jinja(messages_orig, tools, chat_template_kwargs=None):
print(f"Warning: Jinja template raised an exception: {msg}")
return ""
global cached_chat_template
from jinja2.ext import Extension
from jinja2.ext import Extension, loopcontrols
class IgnoreGenerationTags(Extension):
tags = {"generation"}
def parse(self, parser):
parser.stream.skip(1)
return parser.parse_statements( ("name:endgeneration",), drop_needle=True)
from jinja2.sandbox import ImmutableSandboxedEnvironment
jinja_env = ImmutableSandboxedEnvironment(trim_blocks=True, lstrip_blocks=True, extensions=[IgnoreGenerationTags])
jinja_env = ImmutableSandboxedEnvironment(trim_blocks=True, lstrip_blocks=True, extensions=[IgnoreGenerationTags,loopcontrols])
# sanitize messages to remove none types
messages = json.loads(json.dumps(messages_orig))
for m in messages:

View file

@ -3052,20 +3052,18 @@ void llama_vocab::impl::load(llama_model_loader & ml, const LLM_KV & kv) {
attr = LLAMA_TOKEN_ATTR_USER_DEFINED;
}
//kcpp hack render these
if (t.first == "<|tool_call_start|>" || t.first == "<|tool_call_end|>") {
//kcpp hack: render these special tokens
if (t.first == "<|tool_call_start|>" || t.first == "<|tool_call_end|>"
|| t.first=="<|START_THINKING|>" || t.first=="<|END_THINKING|>"
|| t.first=="<|START_ACTION|>" || t.first=="<|END_ACTION|>"
|| t.first == "[THINK]" || t.first == "[/THINK]"
|| t.first == "<think>" || t.first == "</think>"
|| t.first == "[CALL_ID]" || t.first == "[TOOL_CONTENT]" || t.first == "[TOOL_CALLS]" || t.first == "[ARGS]") {
LLAMA_LOG_WARN("%s: setting token '%s' (%d) attribute to USER_DEFINED (%u), old attributes: %u\n",
__func__, t.first.c_str(), t.second, LLAMA_TOKEN_ATTR_USER_DEFINED, attr);
attr = LLAMA_TOKEN_ATTR_USER_DEFINED;
}
if (t.first == "[THINK]" || t.first == "[/THINK]" || t.first == "<think>" || t.first == "</think>" ||
t.first == "[CALL_ID]" || t.first == "[TOOL_CONTENT]" || t.first == "[TOOL_CALLS]" || t.first == "[ARGS]") {
LLAMA_LOG_WARN("%s: setting token '%s' (%d) attribute to USER_DEFINED (%u), old attributes: %u\n",
__func__, t.first.c_str(), t.second, LLAMA_TOKEN_ATTR_USER_DEFINED, attr);
attr = LLAMA_TOKEN_ATTR_USER_DEFINED;
}
}
// sanity checks