fix: declare Hermes auto image support and migrate running accounts
This commit is contained in:
1 parent
6b8d55fc92
commit
437745bcca
4 files changed
+189
-4
No files matched your search
@@ -19,6 +19,8 @@ class DockerBoundary:
|
||||
def __init__(self):
|
||||
self.containers, self.networks, self.created, self.deleted = {}, {}, [], []
|
||||
self.fail_start = False
|
||||
self.restarted = []
|
||||
self.fail_restart = False
|
||||
|
||||
def __call__(self, request):
|
||||
path, method = request.url.path, request.method
|
||||
@@ -51,6 +53,13 @@ class DockerBoundary:
|
||||
if method == 'GET':
|
||||
return httpx.Response(200, json=info)
|
||||
if method == 'POST':
|
||||
if path.endswith('/restart'):
|
||||
self.restarted.append(key)
|
||||
if self.fail_restart:
|
||||
self.fail_restart = False
|
||||
return httpx.Response(500)
|
||||
elif not path.endswith('/start'):
|
||||
raise AssertionError(path)
|
||||
if self.fail_start:
|
||||
self.fail_start = False
|
||||
return httpx.Response(500)
|
||||
@@ -120,7 +129,7 @@ def test_account_isolation_and_runtime_configuration(boundary):
|
||||
assert config['model'] == {'default': 'auto', 'provider': 'custom:hope-upstream'}
|
||||
assert config['providers']['hope-upstream'] == {'api': 'http://192.168.86.5:2099/v1',
|
||||
'key_env': 'HERMES_UPSTREAM_API_KEY', 'transport': 'codex_responses', 'default_model': 'auto',
|
||||
'models': ['auto'], 'discover_models': False}
|
||||
'models': {'auto': {'supports_vision': True}}, 'discover_models': False}
|
||||
assert config['agent']['reasoning_effort'] == 'none'
|
||||
assert config['terminal'] == {'backend': 'local', 'cwd': '/workspace'}
|
||||
assert {'memory', 'browser', 'web', 'terminal', 'file', 'skills'} <= set(config['platform_toolsets']['api_server'])
|
||||
@@ -209,6 +218,68 @@ def test_owned_container_cannot_rotate_missing_private_secret(boundary):
|
||||
assert len(docker.created) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('models', [
|
||||
['auto', 'text-only'],
|
||||
{'auto': {'supports_vision': False, 'context_window': 32768}, 'text-only': {'supports_vision': False}},
|
||||
])
|
||||
def test_auto_vision_migration_preserves_settings_and_reloads_once(boundary, models):
|
||||
p, docker, _ = boundary
|
||||
original = asyncio.run(p.ensure(ALICE))
|
||||
private, home, workspace = p._paths(ALICE)
|
||||
config = yaml.safe_load((home / 'config.yaml').read_text())
|
||||
config['providers']['hope-upstream']['models'] = models
|
||||
config['model']['default'] = 'text-only'
|
||||
config['agent']['reasoning_effort'] = 'high'
|
||||
config['retained'] = {'private': True}
|
||||
(home / 'config.yaml').write_text(yaml.safe_dump(config))
|
||||
(workspace / 'work.txt').write_text('retained')
|
||||
assert not asyncio.run(p.ready(ALICE))
|
||||
assert asyncio.run(p.ensure(ALICE)) == original
|
||||
result = yaml.safe_load((home / 'config.yaml').read_text())
|
||||
expected = copy.deepcopy(config)
|
||||
if isinstance(models, list):
|
||||
expected['providers']['hope-upstream']['models'] = {m: {} for m in models}
|
||||
expected['providers']['hope-upstream']['models']['auto']['supports_vision'] = True
|
||||
assert result == expected
|
||||
assert 'supports_vision' not in result['model']
|
||||
assert docker.restarted == ['id-' + container_name(ALICE)]
|
||||
assert not docker.deleted and len(docker.created) == 1
|
||||
assert (workspace / 'work.txt').read_text() == 'retained'
|
||||
assert not p._reload_marker(ALICE).exists()
|
||||
assert asyncio.run(p.ready(ALICE))
|
||||
asyncio.run(p.ensure(ALICE))
|
||||
assert len(docker.restarted) == 1
|
||||
|
||||
|
||||
def test_failed_reload_is_retried_after_control_restart(boundary):
|
||||
p, docker, _ = boundary
|
||||
original = asyncio.run(p.ensure(ALICE))
|
||||
_, home, _ = p._paths(ALICE)
|
||||
config = yaml.safe_load((home / 'config.yaml').read_text())
|
||||
config['providers']['hope-upstream']['models'] = ['auto']
|
||||
(home / 'config.yaml').write_text(yaml.safe_dump(config))
|
||||
docker.fail_restart = True
|
||||
with pytest.raises(ProvisioningError, match='HTTP 500'):
|
||||
asyncio.run(p.ensure(ALICE))
|
||||
assert p._reload_marker(ALICE).exists()
|
||||
assert not asyncio.run(p.ready(ALICE))
|
||||
restarted = Provisioner(p.state_dir, docker_client=p.docker, health_client=p.health,
|
||||
upstream_api_key='runtime-provider-secret', runtime_uid=p.runtime_uid, runtime_gid=p.runtime_gid)
|
||||
assert asyncio.run(restarted.ensure(ALICE)) == original
|
||||
assert len(docker.restarted) == 2 and not docker.deleted
|
||||
assert not p._reload_marker(ALICE).exists()
|
||||
|
||||
|
||||
def test_vision_patch_skips_unverified_models_and_preserves_metadata():
|
||||
for config in ({'retained': True}, {'providers': {'hope-upstream': {'models': ['text-only']}}}):
|
||||
original = copy.deepcopy(config)
|
||||
assert Provisioner._declare_auto_vision(config) is False
|
||||
assert config == original
|
||||
for models in ('auto', [None], {'auto': None}):
|
||||
with pytest.raises(ValueError):
|
||||
Provisioner._declare_auto_vision({'providers': {'hope-upstream': {'models': models}}})
|
||||
|
||||
|
||||
def test_upstream_runtime_overrides(monkeypatch):
|
||||
monkeypatch.setenv('HERMES_UPSTREAM_URL', 'http://127.0.0.1:9999/v1')
|
||||
monkeypatch.setenv('HERMES_UPSTREAM_MODEL', 'served-model')
|
||||
|
||||
Reference in new issue
Block a user