71 lines
3.6 KiB
Python
71 lines
3.6 KiB
Python
"""Owner-requested model-only adapter; ordinary Runner CLI and gates unchanged."""
|
|
import os
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
control = Path(os.environ['OWNER_RUNNER_CONTROL']).resolve()
|
|
sys.path.insert(0, str(control))
|
|
from runner.core import Runner
|
|
|
|
ALLOWED_CODEX_MODELS = ('gpt-6.1-sol', 'gpt-6-astra')
|
|
original_llm = Runner.llm
|
|
|
|
def owner_model_llm(self, task_id, role, service, prompt, cwd, schema):
|
|
if service == 'claude' and role == 'commander':
|
|
schema = json.loads(json.dumps(schema))
|
|
schema['required'] += ['codex_model', 'codex_model_reason']
|
|
schema['properties']['codex_model'] = {'type': 'string', 'enum': list(ALLOWED_CODEX_MODELS)}
|
|
schema['properties']['codex_model_reason'] = {'type': 'string', 'minLength': 1}
|
|
prompt = ('Owner-authorized model policy: You, Claude Opus 5.5, select the Codex worker model for this task. '
|
|
'Default gpt-6.1-sol. Select gpt-6-astra only when task difficulty warrants it; '
|
|
'state concrete reasons and consider quality, time and usage. Return codex_model and codex_model_reason '
|
|
'with the ordinary decision. Model choice does not authorize a run, repair, cap change or acceptance waiver.\n' + prompt)
|
|
if service == 'codex':
|
|
row = self.db.execute(
|
|
"SELECT data FROM events WHERE task_id=? AND event='commander_proposal' ORDER BY id DESC LIMIT 1",
|
|
(task_id,)).fetchone()
|
|
if not row:
|
|
raise ValueError('Codex model selection requires recorded Claude commander decision')
|
|
decision = json.loads(row[0])['decision']
|
|
chosen = decision.get('codex_model')
|
|
if decision.get('task_id') != task_id or decision.get('action') != 'run' or chosen not in ALLOWED_CODEX_MODELS or not str(decision.get('codex_model_reason', '')).strip():
|
|
raise ValueError('A recorded Claude run decision with explicit model and reason is required')
|
|
prompt = ("Recorded Claude commander run direction for this exact fixed task. Apply within the immutable spec, scope and acceptance; do not widen them.\n" + json.dumps(decision, ensure_ascii=False) + "\n" + prompt)
|
|
self._owner_codex_model = chosen
|
|
try:
|
|
return original_llm(self, task_id, role, service, prompt, cwd, schema)
|
|
finally:
|
|
del self._owner_codex_model
|
|
return original_llm(self, task_id, role, service, prompt, cwd, schema)
|
|
|
|
Runner.llm = owner_model_llm
|
|
original = Runner.provider_argv
|
|
|
|
def owner_model_argv(self, service, role, runtime, schema):
|
|
argv = original(self, service, role, runtime, schema)
|
|
if service in ('claude', 'codex'):
|
|
if '--model' in argv:
|
|
position = argv.index('--model')
|
|
del argv[position:position + 2]
|
|
argv += ['--model', 'claude-opus-5-5' if service == 'claude' else getattr(self, '_owner_codex_model', 'gpt-6.1-sol')]
|
|
return argv
|
|
|
|
Runner.provider_argv = owner_model_argv
|
|
original_packet = Runner.packet
|
|
|
|
def packet_with_actual_evidence(self, task_id, role, sha=None):
|
|
packet = original_packet(self, task_id, role, sha)
|
|
extra = os.environ.get('OWNER_REVIEW_SUPPLEMENT')
|
|
if role == 'reviewer' and extra:
|
|
prefix, data = packet.split('\nDATA:\n', 1)
|
|
body = json.loads(data)
|
|
body['coordinator_actual_runtime_evidence'] = json.loads(Path(extra).read_text())
|
|
assert len(json.dumps(body).encode()) < 500000, 'unchanged complete packet size guard'
|
|
packet = prefix + '\nDATA:\n' + json.dumps(body, ensure_ascii=False)
|
|
return packet
|
|
|
|
Runner.packet = packet_with_actual_evidence
|
|
from runner.cli import main
|
|
main()
|