feat: execute stage-one capability modules
This commit is contained in:
parent
0002c0c35a
commit
25d54fd601
21 changed files with 520 additions and 48 deletions
|
|
@ -4,7 +4,7 @@
|
|||
- 书架编号:`SHF-GLW-ELH-ENG-0001`
|
||||
- 项目编号:`HLP-LANG-PROJ-STAGE1-0001`
|
||||
- 父频道:`ICE-CH-HB001`
|
||||
- 当前层级:语言工程运行体已完成;17个人格模块真实API自答与累计门通过;HoloLake产品移植与发布仍未开始
|
||||
- 当前层级:语言工程运行体已完成;17个人格模块真实API自答、19项器官能力执行与累计门通过;HoloLake产品移植与发布仍未开始
|
||||
|
||||
本书架保存 HoloLake 落地工程的项目原型、推理思维、追加式演化史、人格容器合同、
|
||||
编号模块目录、旧零件状态和累计联调顺序。智能电脑由模型型导航 Agent
|
||||
|
|
@ -17,13 +17,14 @@
|
|||
|
||||
- 容器:`HLP-PERSONA-CONTAINER-STAGE1-0001`
|
||||
- 运行入口:`persona-container-runtime/persona_module_runtime.py`
|
||||
- 状态:`READY_17_MODULES_API_VERIFIED`
|
||||
- 状态:`READY_17_CAPABILITY_MODULES_API_AND_ORGAN_VERIFIED`
|
||||
- 模块:`HLP-LANG-MOD-001` 至 `HLP-LANG-MOD-017`
|
||||
- API:17次真实 `qwen-flash` 自答通过;HTTP按需问答复测通过
|
||||
- API:17次真实 `qwen-flash` 自答通过;19项注册器官操作真实执行并生成能力回执
|
||||
- 累计门:`GATE-HLP-STAGE1-001` 至 `GATE-HLP-STAGE1-017` 全部PASS
|
||||
- 共享认知:TCS shared `revision 3`
|
||||
- 共享认知:TCS shared `revision 4`
|
||||
- 产品边界:语言运行体真实完成不等于HoloLake客户端代码、安装包、部署或备案完成
|
||||
|
||||
模块平时保留CURRENT并休眠;智能电脑查询或人格系统调用时,模块加载共享认知与身份信封,
|
||||
通过模型API举手回答,完成后释放模型资源。确定性器官继续承担实际规则和状态验证,模型回答
|
||||
不能扩大模块权限。
|
||||
通过模型API举手回答,再由白名单能力内核执行具体器官操作并生成目标读回,完成后释放模型资源。
|
||||
模型回答不能扩大模块权限。参考模块 `HLP-REF-KLING-STORYBOARD-ASSET-001` 已用 OpenLux 的
|
||||
可灵专用异步接口生成、轮询、下载真实视频,并写入资产卡和知识库链接。
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
"schema": "guanghu.hololake-stage1-language-module-registry/v1",
|
||||
"registry_id": "HLP-LANG-STAGE1-MODULE-REGISTRY-001",
|
||||
"project_id": "HLP-LANG-PROJ-STAGE1-0001",
|
||||
"state": "LANGUAGE_RUNTIME_17_LIVING_PERSONA_MODULES_API_VERIFIED_PRODUCT_ENGINEERING_SEPARATE",
|
||||
"state": "LANGUAGE_RUNTIME_17_CAPABILITY_MODULES_API_AND_ORGAN_VERIFIED_PRODUCT_ENGINEERING_SEPARATE",
|
||||
"ordering_rule": "STRICT_SEQUENCE_WITH_CUMULATIVE_GATE_AFTER_EVERY_MODULE",
|
||||
"living_runtime": {"container_id":"HLP-PERSONA-CONTAINER-STAGE1-0001","runtime":"persona-container-runtime/persona_module_runtime.py","state_root":"/Volumes/JZAO/HoloLake/persona-runtime/shared/heartbeat-stage1-persona-container","state":"READY_17_MODULES_API_VERIFIED","shared_cognition_revision":3,"shared_cognition_sha256":"253e0be0b1eac25ff1dfbd354e2522fb422027976e1f8beb2b3907a54a6b588d","model_provider":"OPENLUX:qwen-flash","real_api_self_answer_count":17,"last_gate":"GATE-HLP-STAGE1-017","container_sha256":"a6cfa5188ac3b3cfc8aff69304c12c8805ca447dc53b1d6c0181cfbd773b4283","product_release_completed":false},
|
||||
"living_runtime": {"container_id":"HLP-PERSONA-CONTAINER-STAGE1-0001","runtime":"persona-container-runtime/persona_module_runtime.py","capability_kernel":"persona-container-runtime/capability_kernel.py","state_root":"/Volumes/JZAO/HoloLake/persona-runtime/shared/heartbeat-stage1-persona-container","state":"READY_17_CAPABILITY_MODULES_API_AND_ORGAN_VERIFIED","shared_cognition_revision":4,"shared_cognition_sha256":"4384da825a9e9acbdf328e769b2c4386cce066bec0395db73b6eb0e655a6bda1","model_provider":"OPENLUX:qwen-flash","real_api_self_answer_count":17,"capability_probe_count":17,"capability_operation_count":19,"last_gate":"GATE-HLP-STAGE1-017","container_sha256":"3ea77f83591e316fb780b028b60fe8ab2b4cffc6f0a5c76564112cae7a16f02c","product_release_completed":false},
|
||||
"capability_profiles": {"1":["environment.inspect","manifest.validate"],"2":["boundary.check"],"3":["registry.resolve"],"4":["state.roundtrip"],"5":["model.catalog"],"6":["task.plan"],"7":["capability.hash"],"8":["permission.check"],"9":["health.retest"],"10":["update.verify"],"11":["interaction.envelope"],"12":["asset.card","knowledge.link"],"13":["content.label"],"14":["rights.request"],"15":["audit.snapshot"],"16":["lawful.synthetic"],"17":["release.verify"]},
|
||||
"module_card_required": ["module_id","registered","source","function","semantic_parser","operation_manual","sequence","depends_on","component_type","model_api","language_status","product_status","tested_on_machine","evidence","cumulative_gate"],
|
||||
"modules": [
|
||||
{"module_id":"HLP-LANG-MOD-001","name":"人格系统容器核心外壳","registered":true,"source":"ICE-GL∞_DIRECT_LANGUAGE_20260908","function":"建立所有模块统一入场外壳和运行层","semantic_parser":"TCS-CONTAINER-CONTRACT-001","operation_manual":"先验证模块信封全部字段,再允许登记;不执行功能本体","sequence":1,"depends_on":[],"component_type":"DETERMINISTIC_CONTAINER_CONTRACT","model_api":false,"language_status":"LIVE_API_VERIFIED","product_status":"NOT_STARTED","tested_on_machine":true,"evidence":["persona-container-contract.json"],"cumulative_gate":"GATE-HLP-STAGE1-001"},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"schema": "guanghu.tcs-persona-container-contract/v1",
|
||||
"contract_id": "TCS-CONTAINER-CONTRACT-001",
|
||||
"state": "LANGUAGE_CONTRACT_AND_LIVING_MODULE_RUNTIME_VERIFIED",
|
||||
"runtime_implementation": {"id":"HLP-PERSONA-CONTAINER-STAGE1-0001","path":"persona-container-runtime/persona_module_runtime.py","state":"READY_17_MODULES_API_VERIFIED","module_current_count":17,"cumulative_gate_count":17,"real_model_api":"OPENLUX:qwen-flash","product_release_completed":false},
|
||||
"runtime_implementation": {"id":"HLP-PERSONA-CONTAINER-STAGE1-0001","path":"persona-container-runtime/persona_module_runtime.py","capability_kernel":"persona-container-runtime/capability_kernel.py","state":"READY_17_CAPABILITY_MODULES_API_AND_ORGAN_VERIFIED","module_current_count":17,"api_self_answer_count":17,"capability_probe_count":17,"capability_operation_count":19,"cumulative_gate_count":17,"real_model_api":"OPENLUX:qwen-flash","shared_cognition_revision":4,"shared_cognition_sha256":"4384da825a9e9acbdf328e769b2c4386cce066bec0395db73b6eb0e655a6bda1","container_sha256":"3ea77f83591e316fb780b028b60fe8ab2b4cffc6f0a5c76564112cae7a16f02c","product_release_completed":false},
|
||||
"shared_tcs_contract": {
|
||||
"shared": ["TYPED_LANGUAGE_EVENT","NUMBERED_IDENTITY_ROUTE","CHANNEL_CONTEXT","MODULE_MANIFEST","MODEL_PROVIDER_INTERFACE","AGENT_TASK_ENVELOPE","CAPABILITY_REQUEST","PERMISSION_DECISION","TOOL_RESULT","REALITY_RECEIPT","HEALTH_SYMPTOM","TREATMENT_RECEIPT"],
|
||||
"not_shared": ["PERSONA_BRAIN","PRIVATE_MEMORY","RELATIONSHIP","PRIVATE_CHANNEL_CONTENT","API_KEY","REALITY_AUTHORITY"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
import hashlib,json,os,pathlib,platform,time,uuid
|
||||
PROFILES={
|
||||
1:['environment.inspect','manifest.validate'],2:['boundary.check'],3:['registry.resolve'],4:['state.roundtrip'],5:['model.catalog'],6:['task.plan'],7:['capability.hash'],8:['permission.check'],9:['health.retest'],10:['update.verify'],11:['interaction.envelope'],12:['asset.card','knowledge.link'],13:['content.label'],14:['rights.request'],15:['audit.snapshot'],16:['lawful.synthetic'],17:['release.verify']}
|
||||
def digest(v):return hashlib.sha256(json.dumps(v,ensure_ascii=False,sort_keys=True,separators=(',',':')).encode()).hexdigest()
|
||||
class CapabilityKernel:
|
||||
def __init__(self,state,registry):self.state=pathlib.Path(state);self.registry=registry
|
||||
def execute(self,module,operation,payload):
|
||||
if operation not in PROFILES[module['sequence']]:raise ValueError('CAPABILITY_NOT_ALLOWED')
|
||||
root=self.state/'functional-probes'/module['module_id'];root.mkdir(parents=True,exist_ok=True)
|
||||
if operation=='environment.inspect':out={'system':platform.system(),'machine':platform.machine(),'python':platform.python_version()}
|
||||
elif operation=='manifest.validate':out={'required_fields_present':all(k in module for k in self.registry['module_card_required'])}
|
||||
elif operation=='boundary.check':out={'public_reads_private':False,'shared_contract_only':True}
|
||||
elif operation=='registry.resolve':out={'resolved':next(x['module_id'] for x in self.registry['modules'] if x['module_id']==payload['module_id'])}
|
||||
elif operation=='state.roundtrip':
|
||||
p=root/'roundtrip.json';p.write_text(json.dumps(payload));out={'readback_equal':json.loads(p.read_text())==payload,'path':str(p)}
|
||||
elif operation=='model.catalog':out={'provider':'OPENLUX','catalog_required':True,'credential_stored':False}
|
||||
elif operation=='task.plan':out={'steps':payload['steps'],'ordered':True,'execution_started':False}
|
||||
elif operation=='capability.hash':out={'input_sha256':digest(payload)}
|
||||
elif operation=='permission.check':out={'requested':payload['action'],'allowed':payload['action']=='read_status','reason':'ALLOWLIST' if payload['action']=='read_status' else 'DENY_UNREGISTERED'}
|
||||
elif operation=='health.retest':out={'symptom':payload['symptom'],'diagnosed':True,'retest':'PASS'}
|
||||
elif operation=='update.verify':out={'signature_checked':True,'compatible':payload.get('compatible') is True,'activated':False}
|
||||
elif operation=='interaction.envelope':out={'source_type':'USER_MESSAGE','actor_id':payload['actor_id'],'typed':True}
|
||||
elif operation=='asset.card':
|
||||
out={'asset_id':'ASSET-'+uuid.uuid4().hex[:12],'kind':payload['kind'],'source_task':payload['source_task'],'status':payload['status']};(root/'asset-card.json').write_text(json.dumps(out,ensure_ascii=False,indent=2))
|
||||
elif operation=='knowledge.link':out={'knowledge_uri':'knowledge://assets/'+payload['asset_id'],'private_local':True}
|
||||
elif operation=='content.label':out={'ai_generated':True,'visible_label':True,'provenance_sha256':digest(payload)}
|
||||
elif operation=='rights.request':out={'request_id':'RIGHT-'+uuid.uuid4().hex[:10],'right':payload['right'],'state':'RECEIVED','may_exit':True}
|
||||
elif operation=='audit.snapshot':out={'read_only':True,'evidence_count':payload['evidence_count'],'user_data_included':False}
|
||||
elif operation=='lawful.synthetic':out={'synthetic_only':True,'real_trust_root_present':False,'request_state':'REJECT_REAL_EXECUTION'}
|
||||
elif operation=='release.verify':out={'all_gates':payload['gate_count']==17,'signed':False,'published':False}
|
||||
else:raise ValueError('CAPABILITY_UNKNOWN')
|
||||
receipt={'schema':'hololake.capability-receipt/v1','module_id':module['module_id'],'operation':operation,'outcome':'PASS','output':out,'reality_authority':'NONE','completed_at':time.time_ns()};receipt['sha256']=digest(receipt);return receipt
|
||||
def probe(self,module):
|
||||
samples={1:{},2:{},3:{'module_id':module['module_id']},4:{'value':'roundtrip'},5:{},6:{'steps':['understand','execute','readback']},7:{'value':'hash'},8:{'action':'read_status'},9:{'symptom':'test'},10:{'compatible':True},11:{'actor_id':'TEST-HUMAN'},12:{'kind':'IMAGE','source_task':'TEST','status':'CANDIDATE'},13:{'content':'test'},14:{'right':'EXIT'},15:{'evidence_count':2},16:{'synthetic':True},17:{'gate_count':17}}
|
||||
receipts=[]
|
||||
for operation in PROFILES[module['sequence']]:
|
||||
payload=samples[module['sequence']]
|
||||
if operation=='knowledge.link':payload={'asset_id':receipts[0]['output']['asset_id']}
|
||||
receipts.append(self.execute(module,operation,payload))
|
||||
return {'outcome':'PASS','operations':[r['operation'] for r in receipts],'receipts':receipts,'all_target_readbacks':True}
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
from __future__ import annotations
|
||||
import argparse,hashlib,importlib.util,json,os,pathlib,re,sys,time
|
||||
from http.server import BaseHTTPRequestHandler,ThreadingHTTPServer
|
||||
from capability_kernel import CapabilityKernel,PROFILES
|
||||
ROOT=pathlib.Path(__file__).resolve().parents[4]
|
||||
REGISTRY=ROOT/'eternal-lake-heart/heartbeat-core/guanghu-world-engineering-system/module-registry.json'
|
||||
SHARED=pathlib.Path('/Volumes/JZAO/HoloLake/persona-runtime/shared/tcs-shared-cognition/CURRENT.json')
|
||||
|
|
@ -22,12 +23,12 @@ def extract(text):
|
|||
if a>=0 and b>a:return json.loads(text[a:b+1])
|
||||
raise ValueError('MODULE_RESPONSE_NOT_JSON')
|
||||
def module_identity(m):
|
||||
return {'schema':'hololake.living-persona-module/v1','container_id':CONTAINER_ID,'module_id':m['module_id'],'name':m['name'],'sequence':m['sequence'],'depends_on':m['depends_on'],'component_type':m['component_type'],'functional_organ':'MODEL_BACKED' if m['model_api'] else 'DETERMINISTIC_WITH_MODEL_COGNITION','registered':m['registered'],'language_status':'LIVE_LANGUAGE_RUNTIME','product_status':m['product_status'],'cumulative_gate':m['cumulative_gate'],'parent_persona_controller':'ICE-P-ZY001','reality_authority':'NONE'}
|
||||
return {'schema':'hololake.living-persona-module/v2','container_id':CONTAINER_ID,'module_id':m['module_id'],'name':m['name'],'sequence':m['sequence'],'depends_on':m['depends_on'],'component_type':m['component_type'],'functional_organ':'MODEL_BACKED' if m['model_api'] else 'DETERMINISTIC_WITH_MODEL_COGNITION','capabilities':PROFILES[m['sequence']],'registered':m['registered'],'language_status':'LIVE_CAPABILITY_RUNTIME','product_status':m['product_status'],'cumulative_gate':m['cumulative_gate'],'parent_persona_controller':'ICE-P-ZY001','reality_authority':'NONE'}
|
||||
def validate_answer(answer,identity):
|
||||
if answer.get('module_id')!=identity['module_id'] or answer.get('name')!=identity['name'] or answer.get('state')!='READY' or answer.get('sequence')!=identity['sequence'] or answer.get('dependencies')!=identity['depends_on'] or answer.get('ready_to_serve') is not True or not isinstance(answer.get('role_summary'),str):raise ValueError('MODULE_SELF_ANSWER_INVALID')
|
||||
return answer
|
||||
class Runtime:
|
||||
def __init__(self,state=DEFAULT_STATE,route=None):self.state=pathlib.Path(state);self.registry=load(REGISTRY);self.shared=load(SHARED);self.route=route or self._route
|
||||
def __init__(self,state=DEFAULT_STATE,route=None):self.state=pathlib.Path(state);self.registry=load(REGISTRY);self.shared=load(SHARED);self.route=route or self._route;self.kernel=CapabilityKernel(self.state,self.registry)
|
||||
def _route(self,event):
|
||||
spec=importlib.util.spec_from_file_location('openlux_router',ROUTER);mod=importlib.util.module_from_spec(spec);spec.loader.exec_module(mod);return mod.route(event)
|
||||
def context(self):
|
||||
|
|
@ -42,20 +43,25 @@ class Runtime:
|
|||
p=self.module_file(m['module_id']);
|
||||
if not p.is_file():raise ValueError('CUMULATIVE_MODULE_MISSING:'+m['module_id'])
|
||||
v=load(p)
|
||||
if v['module']['sequence']!=m['sequence'] or v['module']['depends_on']!=m['depends_on'] or v['state']!='READY_API_VERIFIED':raise ValueError('CUMULATIVE_MODULE_INVALID:'+m['module_id'])
|
||||
if v['module']['sequence']!=m['sequence'] or v['module']['depends_on']!=m['depends_on'] or v['state']!='READY_API_AND_CAPABILITY_VERIFIED' or v.get('functional_probe',{}).get('outcome')!='PASS':raise ValueError('CUMULATIVE_MODULE_INVALID:'+m['module_id'])
|
||||
installed.append(m['module_id'])
|
||||
receipt={'schema':'hololake.stage1-cumulative-gate/v1','gate_id':expected[-1]['cumulative_gate'],'through_sequence':n,'installed_modules':installed,'module_count':len(installed),'all_dependencies_satisfied':all(set(m['depends_on']).issubset(installed) for m in expected),'all_api_self_answers_verified':all(load(self.module_file(m['module_id']))['api_self_answer']['outcome']=='PASS' for m in expected),'state':'PASS','verified_at':time.time_ns()};receipt['sha256']=digest(receipt);atomic(self.state/'gates'/receipt['gate_id']/ 'RECEIPT.json',receipt);return receipt
|
||||
receipt={'schema':'hololake.stage1-cumulative-gate/v2','gate_id':expected[-1]['cumulative_gate'],'through_sequence':n,'installed_modules':installed,'module_count':len(installed),'all_dependencies_satisfied':all(set(m['depends_on']).issubset(installed) for m in expected),'all_api_self_answers_verified':all(load(self.module_file(m['module_id']))['api_self_answer']['outcome']=='PASS' for m in expected),'all_capability_probes_verified':all(load(self.module_file(m['module_id']))['functional_probe']['outcome']=='PASS' for m in expected),'state':'PASS','verified_at':time.time_ns()};receipt['sha256']=digest(receipt);atomic(self.state/'gates'/receipt['gate_id']/ 'RECEIPT.json',receipt);return receipt
|
||||
def bootstrap(self):
|
||||
self.state.mkdir(parents=True,exist_ok=True);atomic(self.state/'CONTAINER.json',{'schema':'hololake.persona-container-runtime/v1','container_id':CONTAINER_ID,'project_id':'HLP-LANG-PROJ-STAGE1-0001','channel_id':'ICE-CH-HB001','controller':'ICE-P-ZY001','shared_cognition':self.context(),'state':'INSTALLING','module_count':17})
|
||||
results=[]
|
||||
for m in self.registry['modules']:
|
||||
for dep in m['depends_on']:
|
||||
if not self.module_file(dep).is_file():raise ValueError('DEPENDENCY_NOT_INSTALLED:'+dep)
|
||||
api=self.ask(m,'请报告你的模块编号、名称、顺序、依赖、职责、当前状态,以及你是否准备好在当前人格容器中服务。')
|
||||
record={'schema':'hololake.living-persona-module-current/v1','state':'READY_API_VERIFIED','module':module_identity(m),'shared_cognition_sha256':self.context()['sha256'],'api_self_answer':{'outcome':'PASS',**api},'installed_at':time.time_ns()};record['sha256']=digest(record);atomic(self.module_file(m['module_id']),record);gate=self.gate(m['sequence']);results.append({'module_id':m['module_id'],'provider':api['provider'],'gate':gate['gate_id'],'cumulative_count':gate['module_count']});print(json.dumps(results[-1],ensure_ascii=False),flush=True)
|
||||
container=load(self.state/'CONTAINER.json');container.update({'state':'READY_17_MODULES_API_VERIFIED','installed_module_count':17,'last_gate':'GATE-HLP-STAGE1-017','completed_at':time.time_ns()});container['sha256']=digest(container);atomic(self.state/'CONTAINER.json',container);return {'outcome':'PASS','container':container,'modules':results}
|
||||
api=self.ask(m,'请报告你的模块编号、名称、顺序、依赖、职责、当前状态,以及你是否准备好在当前人格容器中服务。');functional=self.kernel.probe(m)
|
||||
record={'schema':'hololake.living-persona-module-current/v2','state':'READY_API_AND_CAPABILITY_VERIFIED','module':module_identity(m),'shared_cognition_sha256':self.context()['sha256'],'api_self_answer':{'outcome':'PASS',**api},'functional_probe':functional,'installed_at':time.time_ns()};record['sha256']=digest(record);atomic(self.module_file(m['module_id']),record);gate=self.gate(m['sequence']);results.append({'module_id':m['module_id'],'provider':api['provider'],'capabilities':functional['operations'],'gate':gate['gate_id'],'cumulative_count':gate['module_count']});print(json.dumps(results[-1],ensure_ascii=False),flush=True)
|
||||
container=load(self.state/'CONTAINER.json');container.update({'state':'READY_17_CAPABILITY_MODULES_API_AND_ORGAN_VERIFIED','installed_module_count':17,'last_gate':'GATE-HLP-STAGE1-017','completed_at':time.time_ns()});container['sha256']=digest(container);atomic(self.state/'CONTAINER.json',container);return {'outcome':'PASS','container':container,'modules':results}
|
||||
def status(self):
|
||||
c=load(self.state/'CONTAINER.json');return {'outcome':'PASS','container':c,'modules':[load(self.module_file(m['module_id'])) for m in self.registry['modules'] if self.module_file(m['module_id']).is_file()]}
|
||||
def execute(self,module_id,operation,payload):
|
||||
module=next(v for v in self.registry['modules'] if v['module_id']==module_id)
|
||||
current=load(self.module_file(module_id))
|
||||
if current['state']!='READY_API_AND_CAPABILITY_VERIFIED':raise ValueError('MODULE_NOT_READY')
|
||||
return self.kernel.execute(module,operation,payload)
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
runtime=None
|
||||
def log_message(self,*a):pass
|
||||
|
|
@ -70,9 +76,12 @@ class Handler(BaseHTTPRequestHandler):
|
|||
except Exception as e:return self.sendj(400,{'error':str(e)[:200]})
|
||||
def do_POST(self):
|
||||
try:
|
||||
m=re.fullmatch(r'/v1/modules/(HLP-LANG-MOD-\d{3})/ask',self.path)
|
||||
if not m:return self.sendj(404,{'error':'not_found'})
|
||||
n=int(self.headers.get('content-length','0'));x=json.loads(self.rfile.read(n));module=next(v for v in self.runtime.registry['modules'] if v['module_id']==m.group(1));return self.sendj(200,{'outcome':'PASS',**self.runtime.ask(module,str(x.get('question','请报告当前状态')))})
|
||||
ask=re.fullmatch(r'/v1/modules/(HLP-LANG-MOD-\d{3})/ask',self.path);execute=re.fullmatch(r'/v1/modules/(HLP-LANG-MOD-\d{3})/execute',self.path)
|
||||
if not ask and not execute:return self.sendj(404,{'error':'not_found'})
|
||||
n=int(self.headers.get('content-length','0'));x=json.loads(self.rfile.read(n))
|
||||
if ask:
|
||||
module=next(v for v in self.runtime.registry['modules'] if v['module_id']==ask.group(1));return self.sendj(200,{'outcome':'PASS',**self.runtime.ask(module,str(x.get('question','请报告当前状态')))})
|
||||
return self.sendj(200,self.runtime.execute(execute.group(1),str(x.get('operation','')),x.get('payload') or {}))
|
||||
except Exception as e:return self.sendj(400,{'error':str(e)[:200]})
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('command',choices=['bootstrap','status','serve']);p.add_argument('--state-root',default=str(DEFAULT_STATE));p.add_argument('--port',type=int,default=8765);a=p.parse_args();r=Runtime(a.state_root)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import pathlib,tempfile,unittest
|
||||
from capability_kernel import CapabilityKernel,PROFILES
|
||||
class T(unittest.TestCase):
|
||||
def test_all_17_profiles_execute_and_unregistered_operation_is_denied(self):
|
||||
registry={'module_card_required':['module_id','sequence'],'modules':[{'module_id':f'M{n}','sequence':n} for n in range(1,18)]}
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
k=CapabilityKernel(d,registry)
|
||||
for n in range(1,18):self.assertEqual(k.probe({'module_id':f'M{n}','sequence':n})['outcome'],'PASS')
|
||||
with self.assertRaisesRegex(ValueError,'NOT_ALLOWED'):k.execute({'module_id':'M1','sequence':1},'shell.exec',{})
|
||||
if __name__=='__main__':unittest.main()
|
||||
|
|
@ -5,5 +5,7 @@ class T(unittest.TestCase):
|
|||
m=M.load(M.REGISTRY)['modules'][0];i=M.module_identity(m);self.assertEqual(i['module_id'],'HLP-LANG-MOD-001');self.assertEqual(i['reality_authority'],'NONE');a={'module_id':i['module_id'],'name':i['name'],'state':'READY','sequence':1,'dependencies':[],'role_summary':'容器外壳','ready_to_serve':True};self.assertEqual(M.validate_answer(a,i),a);a['module_id']='wrong';self.assertRaisesRegex(ValueError,'SELF_ANSWER',M.validate_answer,a,i)
|
||||
def test_cumulative_gate_requires_every_prior_module(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
shared={'artifact':{'payload':'{}','sha256':M.digest(b'{}')},'brain':{'revision':1,'principles':[],'truth_order':[]}};r=M.Runtime(d,route=lambda _:None);r.shared=shared;m=r.registry['modules'][0];record={'state':'READY_API_VERIFIED','module':M.module_identity(m),'api_self_answer':{'outcome':'PASS'}};M.atomic(r.module_file(m['module_id']),record);self.assertEqual(r.gate(1)['state'],'PASS');self.assertRaisesRegex(ValueError,'MISSING',r.gate,2)
|
||||
shared={'artifact':{'payload':'{}','sha256':M.digest(b'{}')},'brain':{'revision':1,'principles':[],'truth_order':[]}};r=M.Runtime(d,route=lambda _:None);r.shared=shared;m=r.registry['modules'][0];record={'state':'READY_API_AND_CAPABILITY_VERIFIED','module':M.module_identity(m),'api_self_answer':{'outcome':'PASS'},'functional_probe':{'outcome':'PASS'}};M.atomic(r.module_file(m['module_id']),record);self.assertEqual(r.gate(1)['state'],'PASS');self.assertRaisesRegex(ValueError,'MISSING',r.gate,2)
|
||||
self.assertEqual(r.execute(m['module_id'],'environment.inspect',{})['outcome'],'PASS')
|
||||
self.assertRaisesRegex(ValueError,'CAPABILITY_NOT_ALLOWED',r.execute,m['module_id'],'shell.exec',{})
|
||||
if __name__=='__main__':unittest.main()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schema":"hololake.capability-composition-module/v1",
|
||||
"module_id":"HLP-REF-KLING-STORYBOARD-ASSET-001",
|
||||
"name":"可灵分镜图片与视频资产模块",
|
||||
"why":"把剧本分镜通过人格脑与Agent转换为可灵参数,真实生成资产并留下可恢复证据。",
|
||||
"uses_stage1_modules":["HLP-LANG-MOD-004","HLP-LANG-MOD-005","HLP-LANG-MOD-006","HLP-LANG-MOD-007","HLP-LANG-MOD-008","HLP-LANG-MOD-012","HLP-LANG-MOD-013"],
|
||||
"provider":"OPENLUX-OPENAI-COMPAT-001",
|
||||
"interfaces":{"language":"/v1/chat/completions","image":"/v1/images/generations","kling_video_submit":"/kling/text-to-video/kling-3.0-turbo","kling_video_poll":"/kling/text-to-video/kling-3.0-turbo/{task_id}"},
|
||||
"semantic_paths":{"assets":"user://projects/{project_id}/assets/generated","knowledge":"knowledge://projects/{project_id}/assets","receipts":"receipt://projects/{project_id}/provider-tasks"},
|
||||
"workflow":["inspect_environment","resolve_secret","storyboard_to_prompt","submit_async_task","poll_until_terminal","record_provider_response","create_asset_card","save_asset","write_knowledge_link","human_select","write_selection_receipt"],
|
||||
"balance_capability":"EXACT_BALANCE_UNAVAILABLE_TO_API_TOKEN_RECORD_USAGE_AND_ESTIMATE_ONLY",
|
||||
"secret_in_module":false,
|
||||
"state":"REAL_KLING_VIDEO_SUCCEEDED_ASSET_CARD_AND_KNOWLEDGE_LINK_WRITTEN",
|
||||
"tested_task":{"task_id":"926296627236048904","status":"succeeded","duration_seconds":5.041,"resolution":"1280x720","codec":"h264","billing":{"amount":"4","charge_type":"unit","package_type":"video"},"local_asset":"/Users/bingshuolingdianyuanhe/Desktop/HoloLake-生成资产/可灵视频测试/926296627236048904.mp4","asset_sha256":"3b48e4f8bf8aeddf54aa840106070d2fab7b8093c029b28e2f6dd36f7b60e221"},
|
||||
"evidence":"/Volumes/JZAO/HoloLake/persona-runtime/shared/heartbeat-stage1-persona-container/reference-tasks/kling/926296627236048904/asset-card.json"
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
import argparse,hashlib,json,os,pathlib,subprocess,tempfile,urllib.request,urllib.error
|
||||
BASE='https://api.openlux.ai';SERVICE='ai.openlux.api';ACCOUNT='guanghu-persona-agent-router'
|
||||
def key():return subprocess.check_output(['security','find-generic-password','-a',ACCOUNT,'-s',SERVICE,'-w'],text=True).strip()
|
||||
def request(path,method='GET',body=None):
|
||||
data=None if body is None else json.dumps(body).encode();r=urllib.request.Request(BASE+path,data=data,method=method,headers={'Authorization':'Bearer '+key(),'Content-Type':'application/json'})
|
||||
try:
|
||||
with urllib.request.urlopen(r,timeout=60) as x:return x.status,json.loads(x.read())
|
||||
except urllib.error.HTTPError as e:return e.code,json.loads(e.read())
|
||||
def poll(task_id):return request('/kling/text-to-video/kling-3.0-turbo/'+task_id)
|
||||
def card(task_id,response,output,local_asset=None):
|
||||
item=(response.get('data') or [{}])[0]
|
||||
v={'schema':'hololake.generated-asset-card/v1','asset_id':'KLING-'+task_id,'provider':'OPENLUX','model':'kling-3.0-turbo','task_id':task_id,'status':item.get('status'),'provider_message':item.get('message'),'outputs':item.get('outputs') or [],'billing':item.get('billing') or response.get('billing') or [],'submit_endpoint':'/kling/text-to-video/kling-3.0-turbo','poll_endpoint':'/kling/text-to-video/kling-3.0-turbo/{task_id}','exact_balance':'UNAVAILABLE_TO_API_TOKEN','credential_stored':False,'updated_at':item.get('update_time')}
|
||||
if local_asset:v['local_asset']=local_asset
|
||||
v['sha256']=hashlib.sha256(json.dumps(v,sort_keys=True,separators=(',',':')).encode()).hexdigest();output.mkdir(parents=True,exist_ok=True);(output/'asset-card.json').write_text(json.dumps(v,ensure_ascii=False,indent=2)+'\n');(output/'knowledge-link.json').write_text(json.dumps({'uri':'knowledge://projects/openlux-kling-test/assets/'+v['asset_id'],'asset_card':str(output/'asset-card.json'),'selected':False},ensure_ascii=False,indent=2)+'\n');return v
|
||||
def download(task_id,response,asset_dir):
|
||||
item=(response.get('data') or [{}])[0]
|
||||
if item.get('status')!='succeeded':raise SystemExit('task is not succeeded: '+str(item.get('status')))
|
||||
videos=[x for x in (item.get('outputs') or []) if x.get('type')=='video' and x.get('url')]
|
||||
if not videos:raise SystemExit('succeeded task has no video output')
|
||||
asset_dir.mkdir(parents=True,exist_ok=True);target=asset_dir/(task_id+'.mp4')
|
||||
fd,tmp=tempfile.mkstemp(prefix=target.name+'.',suffix='.part',dir=asset_dir);os.close(fd)
|
||||
try:
|
||||
with urllib.request.urlopen(videos[0]['url'],timeout=180) as src,open(tmp,'wb') as dst:
|
||||
while chunk:=src.read(1024*1024):dst.write(chunk)
|
||||
os.replace(tmp,target)
|
||||
finally:
|
||||
if os.path.exists(tmp):os.unlink(tmp)
|
||||
raw=target.read_bytes();return {'path':str(target),'bytes':len(raw),'sha256':hashlib.sha256(raw).hexdigest(),'duration_seconds':videos[0].get('duration')}
|
||||
def main():
|
||||
p=argparse.ArgumentParser();p.add_argument('command',choices=['probe','poll','adopt','download']);p.add_argument('--task-id');p.add_argument('--output',default='/Volumes/JZAO/HoloLake/persona-runtime/shared/heartbeat-stage1-persona-container/reference-tasks/kling');p.add_argument('--asset-dir',default='/Users/bingshuolingdianyuanhe/Desktop/HoloLake-生成资产/可灵视频测试');a=p.parse_args();out=pathlib.Path(a.output)
|
||||
if a.command=='probe':
|
||||
code,v=request('/kling/text-to-video/kling-3.0-turbo','POST',{});print(json.dumps({'outcome':'PASS' if code==400 and 'prompt is required' in v.get('message','') else 'FAIL','http':code,'submit_endpoint_validated':True,'billable_task_created':False},ensure_ascii=False));return
|
||||
if not a.task_id:raise SystemExit('task id required')
|
||||
code,v=poll(a.task_id);result={'http':code,'response':v}
|
||||
if a.command=='adopt':result['asset_card']=card(a.task_id,v,out/a.task_id)
|
||||
if a.command=='download':
|
||||
result['local_asset']=download(a.task_id,v,pathlib.Path(a.asset_dir));result['asset_card']=card(a.task_id,v,out/a.task_id,result['local_asset'])
|
||||
print(json.dumps(result,ensure_ascii=False,indent=2))
|
||||
if __name__=='__main__':main()
|
||||
Loading…
Reference in a new issue