ladder20 complete 28/28 (Qwen3-8B pool): fixes en route — tau2 off-loop executor, double-encoded tool args, shared adapter cache; swe real-model 0.0 (oracle path verified 1.0)
This commit is contained in:
parent
0e1e31ba10
commit
111336cbee
@ -123,8 +123,17 @@ class Tau2Environment(Environment):
|
|||||||
task = Task.model_validate(task_json if not isinstance(task_json, str)
|
task = Task.model_validate(task_json if not isinstance(task_json, str)
|
||||||
else json.loads(task_json))
|
else json.loads(task_json))
|
||||||
domain = (sample.metadata or {}).get('domain') or 'airline'
|
domain = (sample.metadata or {}).get('domain') or 'airline'
|
||||||
res = run_task(domain=domain, task=task, agent='llm_agent',
|
# the official engine is SYNCHRONOUS and calls our adapter back via a
|
||||||
user='user_simulator', max_steps=max_turns)
|
# private event loop in a worker thread; run it off the main loop so it
|
||||||
|
# never blocks the runner's other benches
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
|
||||||
|
res = await loop.run_in_executor(
|
||||||
|
pool, lambda: run_task(domain=domain, task=task,
|
||||||
|
agent='llm_agent', user='user_simulator',
|
||||||
|
max_steps=max_turns))
|
||||||
rewards = {}
|
rewards = {}
|
||||||
try:
|
try:
|
||||||
info = res.reward_info
|
info = res.reward_info
|
||||||
|
|||||||
@ -25,6 +25,10 @@ from .output import ModelOutput, ToolCall, Usage
|
|||||||
|
|
||||||
ADAPTER_REGISTRY = EvalRegistry('model adapter')
|
ADAPTER_REGISTRY = EvalRegistry('model adapter')
|
||||||
|
|
||||||
|
_ADAPTER_CACHE = {} # spec -> shared instance; keeps pool round-robin state
|
||||||
|
# GLOBAL across benches (else each pool restarts at the
|
||||||
|
# first backend and starves the rest)
|
||||||
|
|
||||||
|
|
||||||
def register_adapter(name: str):
|
def register_adapter(name: str):
|
||||||
def decorator(cls):
|
def decorator(cls):
|
||||||
@ -87,9 +91,13 @@ def resolve_adapter(spec: str, deploy_fn=None) -> ModelAdapter:
|
|||||||
endpoint = deploy_fn(m.group('deployer'), m.group('model'))
|
endpoint = deploy_fn(m.group('deployer'), m.group('model'))
|
||||||
spec = f"openai/{endpoint['api_base']}?{endpoint['model']}"
|
spec = f"openai/{endpoint['api_base']}?{endpoint['model']}"
|
||||||
parsed = parse_model_spec(spec)
|
parsed = parse_model_spec(spec)
|
||||||
|
if spec in _ADAPTER_CACHE:
|
||||||
|
return _ADAPTER_CACHE[spec]
|
||||||
cls = ADAPTER_REGISTRY.get(parsed['adapter'])
|
cls = ADAPTER_REGISTRY.get(parsed['adapter'])
|
||||||
key = parsed.get('api_base') and _key_for(parsed['api_base'])
|
key = parsed.get('api_base') and _key_for(parsed['api_base'])
|
||||||
return cls(model=parsed['model'], api_base=parsed['api_base'], api_key=key)
|
inst = cls(model=parsed['model'], api_base=parsed['api_base'], api_key=key)
|
||||||
|
_ADAPTER_CACHE[spec] = inst
|
||||||
|
return inst
|
||||||
|
|
||||||
|
|
||||||
def _key_for(api_base: str) -> str:
|
def _key_for(api_base: str) -> str:
|
||||||
@ -219,6 +227,10 @@ class OpenAICompatible(ModelAdapter):
|
|||||||
args = fn.get('arguments') or '{}'
|
args = fn.get('arguments') or '{}'
|
||||||
try:
|
try:
|
||||||
args_dict = json.loads(args)
|
args_dict = json.loads(args)
|
||||||
|
if isinstance(args_dict, str): # double-encoded JSON string
|
||||||
|
args_dict = json.loads(args_dict)
|
||||||
|
if not isinstance(args_dict, dict):
|
||||||
|
args_dict = {'raw': args_dict}
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
args_dict = {}
|
args_dict = {}
|
||||||
calls.append(ToolCall(id=c.get('id', ''), name=fn.get('name', ''),
|
calls.append(ToolCall(id=c.get('id', ''), name=fn.get('name', ''),
|
||||||
|
|||||||
@ -382,7 +382,16 @@ def _make_adapter(spec: str) -> ModelAdapter:
|
|||||||
- 'openai-pool/<base-url-template>?model' with {port} placeholder:
|
- 'openai-pool/<base-url-template>?model' with {port} placeholder:
|
||||||
e.g. 'openai-pool/http://127.0.0.1:{8123..8130}/v1?Qwen3-8B' -> N ports
|
e.g. 'openai-pool/http://127.0.0.1:{8123..8130}/v1?Qwen3-8B' -> N ports
|
||||||
- else resolve_adapter(spec) single endpoint
|
- else resolve_adapter(spec) single endpoint
|
||||||
|
|
||||||
|
Pooled specs are CACHED per spec: all benches share one pool so the
|
||||||
|
round-robin counter stays global (independent pools would each restart
|
||||||
|
at the first backend and starve the rest).
|
||||||
"""
|
"""
|
||||||
|
from .adapter import _ADAPTER_CACHE as _CACHE
|
||||||
|
|
||||||
|
cache_key = spec
|
||||||
|
if cache_key in _CACHE:
|
||||||
|
return _CACHE[cache_key]
|
||||||
opts = {}
|
opts = {}
|
||||||
while True:
|
while True:
|
||||||
for f in ('!nothink', '!textools'):
|
for f in ('!nothink', '!textools'):
|
||||||
@ -417,6 +426,7 @@ def _make_adapter(spec: str) -> ModelAdapter:
|
|||||||
a.extra['no_think'] = True
|
a.extra['no_think'] = True
|
||||||
if opts.get('!textools'):
|
if opts.get('!textools'):
|
||||||
a.extra['tools_mode'] = 'text'
|
a.extra['tools_mode'] = 'text'
|
||||||
|
_CACHE[cache_key] = adapter
|
||||||
return adapter
|
return adapter
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user