Text Generation
Transformers.js
ONNX
llama
webgpu
q4f16
gptq
tool-calling
experimental
conversational
Instructions to use webbrain-one/webbrain-compass-tiny-v2.1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers.js
How to use webbrain-one/webbrain-compass-tiny-v2.1 with Transformers.js:
// npm i @huggingface/transformers import { pipeline } from '@huggingface/transformers'; // Allocate pipeline const pipe = await pipeline('text-generation', 'webbrain-one/webbrain-compass-tiny-v2.1');
Download integration/minicpm5-tool-parser.mjs from webbrain-one/webbrain-compass-tiny-v2.1: direct link, hf CLI and curl.
- Browser
- Download file 5.31 kB
-
https://huggingface.co/webbrain-one/webbrain-compass-tiny-v2.1/resolve/main/integration/minicpm5-tool-parser.mjs
- Command line
-
hf download hf://webbrain-one/webbrain-compass-tiny-v2.1/integration/minicpm5-tool-parser.mjs
-
curl -L -o minicpm5-tool-parser.mjs https://huggingface.co/webbrain-one/webbrain-compass-tiny-v2.1/resolve/main/integration/minicpm5-tool-parser.mjs
5.31 kB
| // MiniCPM5 native XML uses Python literals for typed parameters. No eval/Function. | |
| export function parseMiniCpmParamValue(input, schema = {}) { | |
| const raw = String(input ?? ''); | |
| const cdata = /^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/.exec(raw); | |
| let decoded=cdata ? cdata[1] : raw; | |
| if(!cdata) { | |
| if(raw.includes('<')) throw Error('Malformed XML parameter: use CDATA for literal markup'); | |
| decoded=raw.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);/gi,(_,entity)=>{ | |
| if(entity.startsWith('#')) { const n=entity[1].toLowerCase()==='x'?parseInt(entity.slice(2),16):parseInt(entity.slice(1),10);return String.fromCodePoint(n); } | |
| return {amp:'&',lt:'<',gt:'>',quot:'"',apos:"'"}[entity]; | |
| }); | |
| if(/&(?!(?:#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);)/i.test(raw)) throw Error('Unescaped XML ampersand'); | |
| } | |
| if(schema.type==='string') return decoded; | |
| const text = decoded.trim(); | |
| if (!text) return ''; | |
| let i = 0; | |
| const ws = () => { while (i < text.length && /\s/u.test(text[i])) i++; }; | |
| const take = char => { ws(); if (text[i++] !== char) throw Error('Invalid literal'); }; | |
| function value(depth = 0) { | |
| if (depth > 32) throw Error('Literal nesting limit'); | |
| ws(); | |
| const c = text[i]; | |
| if (c === "'" || c === '"') { | |
| const quote = text[i++]; let result = ''; | |
| while (i < text.length) { | |
| const ch = text[i++]; | |
| if (ch === quote) return result; | |
| if (ch !== '\\') { result += ch; continue; } | |
| const e = text[i++]; | |
| const simple = { '\\':'\\', "'":"'", '"':'"', n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', '/':'/' }; | |
| if (Object.hasOwn(simple,e)) { result += simple[e]; continue; } | |
| const width = e === 'u' ? 4 : e === 'x' ? 2 : 0; | |
| const hex = text.slice(i,i+width); | |
| if (!width || !new RegExp(`^[a-fA-F0-9]{${width}}$`).test(hex)) throw Error('Invalid escape'); | |
| result += String.fromCharCode(parseInt(hex,16)); i += width; | |
| } | |
| throw Error('Unterminated string'); | |
| } | |
| if (c === '[' || c === '{') { | |
| i++; const array = c === '['; const end = array ? ']' : '}'; | |
| const result = array ? [] : Object.create(null); | |
| ws(); if (text[i] === end) { i++; return array ? result : {...result}; } | |
| while (i < text.length) { | |
| if (array) result.push(value(depth+1)); | |
| else { | |
| ws(); if (!['"',"'"].includes(text[i])) throw Error('Expected string key'); | |
| const key = value(depth+1); | |
| if (Object.hasOwn(result,key)) throw Error('Duplicate key'); | |
| take(':'); result[key] = value(depth+1); | |
| } | |
| ws(); if (text[i] === end) { i++; return array ? result : {...result}; } | |
| take(','); ws(); | |
| if (text[i] === end) { i++; return array ? result : {...result}; } | |
| } | |
| throw Error('Unterminated container'); | |
| } | |
| const scalar = /^(True|False|None|true|false|null)(?![\w])/u.exec(text.slice(i)); | |
| if (scalar) { i += scalar[0].length; return {True:true,False:false,None:null,true:true,false:false,null:null}[scalar[0]]; } | |
| const number = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/u.exec(text.slice(i)); | |
| if (number) { i += number[0].length; const result=Number(number[0]); if(Number.isFinite(result)) return result; } | |
| throw Error('Not a literal'); | |
| } | |
| try { const result=value(); ws(); if(i===text.length) return result; } catch { /* native strings are also unquoted */ } | |
| return text; | |
| } | |
| // Strict standalone adapter. Keep downstream tool schema/approval validation in place. | |
| export function parseMiniCpmToolCalls(text, toolsOrNames) { | |
| const tools=Array.isArray(toolsOrNames)?toolsOrNames:[]; | |
| const allowedNames=Array.isArray(toolsOrNames)?new Set(tools.map(t=>t.function.name)):toolsOrNames; | |
| const schemas=new Map(tools.map(t=>[t.function.name,t.function.parameters || {}])); | |
| const source=String(text ?? '').trim(); | |
| if (!source || source.length>10000 || !(allowedNames instanceof Set)) return []; | |
| // Native MiniCPM may explain an error before emitting the XML tool call. | |
| // Accept that prose, but never skip over a malformed XML call or parameter. | |
| const start=source.indexOf('<function'); | |
| if(start<0 || /<\/?(?:function|param)\b/.test(source.slice(0,start))) return []; | |
| const calls=[]; let cursor=start; | |
| const functions=/<function\s+name=["']([A-Za-z_]\w*)["']\s*>([\s\S]*?)<\/function>/gy; | |
| const params=/<param\s+name=["']([A-Za-z_]\w*)["']\s*>([\s\S]*?)<\/param>/gy; | |
| while(cursor<source.length) { | |
| while (/\s/u.test(source[cursor] || '')) cursor++; | |
| if(cursor===source.length) break; | |
| functions.lastIndex=cursor; const fn=functions.exec(source); | |
| if(!fn || !allowedNames.has(fn[1])) return []; | |
| const args=Object.create(null); let pos=0; | |
| while(pos<fn[2].length) { | |
| while(/\s/u.test(fn[2][pos] || '')) pos++; | |
| if(pos===fn[2].length) break; | |
| params.lastIndex=pos; const param=params.exec(fn[2]); | |
| if(!param || Object.hasOwn(args,param[1])) return []; | |
| try { args[param[1]]=parseMiniCpmParamValue(param[2],schemas.get(fn[1])?.properties?.[param[1]]); } | |
| catch { return []; } | |
| pos=params.lastIndex; | |
| } | |
| calls.push({id:`compass_call_${Date.now()}_${calls.length}`,type:'function',function:{name:fn[1],arguments:JSON.stringify(args)}}); | |
| cursor=functions.lastIndex; | |
| } | |
| return calls; | |
| } | |