ajh-code's picture
Publish Jev-Bonsai-Compass runtime, adapter, card and evidence
b4b0f75 verified
Raw History Blame Contribute Delete
3.5 kB
"""Reusable text-choice and compact arithmetic decisions over one resident model."""
import json,time
from .numeric import applicable,compact_unit,compact_prompt,decode,INSTRUCTION
from .readout import prompt_for,readout
def validate(request):
if not isinstance(request,dict) or set(request)!={'state','question','options'}:raise ValueError('Provide exactly state, question, and options')
if not all(isinstance(request[k],str) and request[k].strip() for k in ['state','question']):raise ValueError('State and question must be nonempty strings')
options=request['options']
if not isinstance(options,list) or not 2<=len(options)<=26:raise ValueError('Provide 2 to 26 options')
if not all(isinstance(o,(list,tuple)) and len(o)==2 and all(isinstance(v,str) and v for v in o) for o in options):raise ValueError('Options must be pairs of nonempty strings')
if len({o[0] for o in options})!=len(options):raise ValueError('Option IDs must be unique')
if len(json.dumps(request))>65536:raise ValueError('Request exceeds the 64 KiB input limit')
class DecisionEngine:
def __init__(self,client):
client.verify_profile()
self.client=client
def decide(self,request):
validate(request)
# One entire decision (including a possible fallback) holds the worker slot.
with self.client.lock:return self._decide(request)
def _decide(self,request):
self.client.calls.clear()
tick=time.perf_counter();start=0;trace={};attempted=applicable(request)
if attempted:
unit=compact_unit(request)
prompt=compact_prompt(request) if unit is not None else INSTRUCTION+'\n'+prompt_for(request['state'],request['question'],request['options']).replace('Answer with the letter of the best option only.','Return only the JSON calculation, or a null expression.')
response=self.client.post('/v1/chat/completions',dict(model='qwen',messages=[dict(role='user',content=prompt)],max_tokens=64 if unit is not None else 96,temperature=0))
choice=response['choices'][0];content=choice['message'].get('content') or ''
trace=dict(tool_expression=content,tool_tokens=(response.get('usage') or {}).get('completion_tokens'),tool_finish_reason=choice['finish_reason'],tool_error=None)
if unit is not None:trace['output_unit']=unit
try:
if choice['finish_reason']=='length':raise ValueError('truncated')
answer,_=decode(json.dumps(dict(expression=content,unit=unit)) if unit is not None else content,request['options'])
return dict(answer=answer,method='numeric-tool',tool_attempted=True,seconds=time.perf_counter()-tick,score=None,trace=trace,calls=self.client.calls[start:])
except (ValueError,TypeError,AssertionError,SyntaxError,ZeroDivisionError,OverflowError,KeyError,IndexError) as exc:trace['tool_error']=str(exc)
result=readout(self.client,request['state'],request['question'],request['options'],.85,dict(cache_prompt=False,top_logprobs=1024))
if result['missing_letters']:raise RuntimeError('Backend did not return all option scores')
return dict(answer=result['argmax'],method='fast',tool_attempted=attempted,seconds=time.perf_counter()-tick,
score=max(p['p'] for p in result['probs']),score_kind='option-relative softmax; not a correctness guarantee',
probs=result['probs'],trace=trace,calls=self.client.calls[start:])