"""显式隔离演示:检索、读取、创建三个任务,再调用真实只读 MCP。 只批准本次运行产生的 tasks.write 权限票据,需要质量验收用 Vault。 脚本仅调用公共 API 契约,不把伪造的完成状态写入 SQLite。 """ import argparse, json, time from pathlib import Path from urllib.request import Request,urlopen def main(args): def api(path,body=None): req=Request(args.base_url+'/api'+path,data=json.dumps(body).encode() if body is not None else None, headers={'Content-Type':'application/json'}) with urlopen(req,timeout=60) as response:return json.load(response) directory=args.data_dir.resolve() if not (directory/'vault/.phase2-fixture').exists():raise SystemExit('Isolated fixture Vault required') core=json.loads((directory/'benchmarks/rag-phase2-v1.json').read_text(encoding='utf-8')) note=next(c for c in core['cases'] if c['case_id']=='deadlock-0')['expected_note_ids'][0] cases=[{'case_id':'retrieval-tasks','prompt':f'按顺序执行:1. 用 rag.search 搜索“死锁”,明确使用 mode=fts;2. 用 notes.read 读取笔记 {note};3. 根据内容用 tasks.create 分别创建且仅创建三个任务,标题严格为“验收-互斥条件”、“验收-循环等待”、“验收-锁顺序”;4. 总结死锁条件并引用搜索来源。请不要调用其他工具,不重复创建。', 'allowed_tools':['rag.search','notes.read','tasks.create'], 'expected_tools':[{'name':'rag.search','arguments':{'query':'死锁','mode':'fts'}},{'name':'notes.read','arguments':{'note_id':note}}]+ [{'name':'tasks.create','arguments':{'title':title}} for title in ['验收-互斥条件','验收-循环等待','验收-锁顺序']], 'citation_required':True,'tasks_created':3,'output_contains':['死锁'],'tags':['rag','notes','tasks','permissions']}] tools=api('/tools')['items']; mcp=next((t for t in tools if t['name'].endswith('.web_search') and t['name'].startswith('mcp.')),None) if mcp: cases.append({'case_id':'mcp-search','prompt':f'调用一次 {mcp["name"]},query 严格使用 Python official documentation tutorial。根据工具真实返回给出一句总结。', 'allowed_tools':[mcp['name']], 'expected_tools':[{'name':mcp['name'],'arguments':{'query':'Python official documentation tutorial'}}], 'tags':['mcp','real-network']}) dataset={'dataset_id':'agent-integration-v1','kind':'agent','version':'1.0.0','description':'Isolated phase2 cross-module Demo; existing MCP binding captured','cases':cases} (directory/'benchmarks/agent-integration-v1.json').write_text(json.dumps(dataset,ensure_ascii=False,indent=2),encoding='utf-8') providers=api('/providers')['items']; provider=next(p for p in providers if p['enabled'] and p['provider_type']!='mock') run=api('/benchmarks/agent/runs',{'dataset_id':dataset['dataset_id'],'provider_id':provider['provider_id'],'model':provider['default_model'], 'max_steps':10,'timeout_seconds':150,'token_budget':10000,'allow_network':True}) approved=set();deadline=time.monotonic()+360 while run['status'] in ['queued','running']: if time.monotonic()>deadline: api('/benchmarks/runs/'+run['run_id']+'/cancel',{});raise RuntimeError('Demo deadline') active=run['config_snapshot'].get('active_agent_run_id') if active: trace=api('/agent/runs/'+active+'/trace') for event in trace['items']: data=event['data'];ticket=data.get('request_id') if event['event']=='PermissionRequired' and data.get('permission')=='tasks.write' and ticket not in approved: api('/agent/runs/'+active+'/permissions/'+ticket,{'decision':'allow_once'});approved.add(ticket) time.sleep(.3);run=api('/benchmarks/runs/'+run['run_id']) report=api('/benchmarks/runs/'+run['run_id']+'/report') report['permission_approvals']=len(approved) report['mcp_present']=bool(mcp) report['tasks']= [{'task_id':t['task_id'],'title':t['title']} for t in api('/tasks')['items'] if t['title'].startswith('验收-')] args.output.write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf-8') print(json.dumps({'metrics':report['metrics'],'cases':report['cases'],'permission_approvals':len(approved)},ensure_ascii=False)) if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--base-url',default='http://127.0.0.1:8017');p.add_argument('--data-dir',type=Path,required=True);p.add_argument('--output',type=Path,required=True);p.add_argument('--execute',action='store_true');args=p.parse_args() if not args.execute:p.error('--execute required; creates three tasks only in the isolated fixture application') if args.base_url not in {'http://127.0.0.1:8017','http://localhost:8017'}:p.error('Use the isolated local acceptance server on port 8017') main(args)