@miller-tech/uap 1.213.0 → 1.215.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +2 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/deliver.d.ts +66 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +227 -7
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/verify.d.ts +5 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +50 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +26 -1
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/delivery/await-run.d.ts +47 -0
- package/dist/delivery/await-run.d.ts.map +1 -1
- package/dist/delivery/await-run.js +392 -2
- package/dist/delivery/await-run.js.map +1 -1
- package/dist/delivery/capability-profile.d.ts +124 -0
- package/dist/delivery/capability-profile.d.ts.map +1 -0
- package/dist/delivery/capability-profile.js +392 -0
- package/dist/delivery/capability-profile.js.map +1 -0
- package/dist/delivery/convergence-loop.d.ts +38 -0
- package/dist/delivery/convergence-loop.d.ts.map +1 -1
- package/dist/delivery/convergence-loop.js +98 -1
- package/dist/delivery/convergence-loop.js.map +1 -1
- package/dist/delivery/epic-controller.d.ts +9 -0
- package/dist/delivery/epic-controller.d.ts.map +1 -1
- package/dist/delivery/epic-controller.js +1 -0
- package/dist/delivery/epic-controller.js.map +1 -1
- package/dist/delivery/epic-mission.d.ts +10 -2
- package/dist/delivery/epic-mission.d.ts.map +1 -1
- package/dist/delivery/epic-mission.js +1 -1
- package/dist/delivery/epic-mission.js.map +1 -1
- package/dist/delivery/escalation.d.ts +8 -0
- package/dist/delivery/escalation.d.ts.map +1 -1
- package/dist/delivery/escalation.js +8 -1
- package/dist/delivery/escalation.js.map +1 -1
- package/dist/delivery/execution-gate.d.ts +29 -0
- package/dist/delivery/execution-gate.d.ts.map +1 -1
- package/dist/delivery/execution-gate.js +237 -9
- package/dist/delivery/execution-gate.js.map +1 -1
- package/dist/delivery/mission-acceptance.d.ts +4 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +35 -1
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/run-state.d.ts +31 -0
- package/dist/delivery/run-state.d.ts.map +1 -1
- package/dist/delivery/run-state.js +49 -0
- package/dist/delivery/run-state.js.map +1 -1
- package/dist/mcp-router/tools/deliver.d.ts.map +1 -1
- package/dist/mcp-router/tools/deliver.js +5 -2
- package/dist/mcp-router/tools/deliver.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lib/llama-upstream.sh +64 -16
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/confidence_escalation.py +57 -0
- package/tools/agents/tests/test_confidence_escalation.py +140 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Tests for the serving-layer recipe runtime (Confidence #1/#5, Fusion #3, selector #2)."""
|
|
2
2
|
import asyncio
|
|
3
3
|
import importlib.util
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
import unittest
|
|
6
7
|
from pathlib import Path
|
|
@@ -24,10 +25,16 @@ spec.loader.exec_module(ce)
|
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
def S(enabled=True, recipe="auto", signal="heuristic", threshold=0.5, fusion_n=3,
|
|
27
|
-
auto_chars=600, model="opus", endpoint="http://x/", key="k", remom_quorum=2
|
|
28
|
+
auto_chars=600, model="opus", endpoint="http://x/", key="k", remom_quorum=2,
|
|
29
|
+
model_slots=None, force_multi_call=False):
|
|
30
|
+
# model_slots defaults to None = UNKNOWN width, which changes nothing. The
|
|
31
|
+
# selector reads this FIELD, never process env, so an ambient
|
|
32
|
+
# UAP_MODEL_SLOTS=1 (what proxy.env now carries on a one-slot box) cannot
|
|
33
|
+
# rewrite the expectations of tests that are not about slot width.
|
|
28
34
|
return ce.Settings(enabled=enabled, recipe=recipe, signal=signal, threshold=threshold,
|
|
29
35
|
fusion_n=fusion_n, remom_quorum=remom_quorum, auto_fusion_chars=auto_chars,
|
|
30
|
-
model=model, endpoint=endpoint, api_key=key
|
|
36
|
+
model=model, endpoint=endpoint, api_key=key,
|
|
37
|
+
model_slots=model_slots, force_multi_call=force_multi_call)
|
|
31
38
|
|
|
32
39
|
|
|
33
40
|
def resp(text):
|
|
@@ -351,5 +358,136 @@ class AdaptationSignalTest(unittest.TestCase): # LLM-Self-Tuning real-time adap
|
|
|
351
358
|
)
|
|
352
359
|
|
|
353
360
|
|
|
361
|
+
class SlotRightSizingTest(unittest.TestCase):
|
|
362
|
+
"""A fan-out recipe assumes its N generations OVERLAP.
|
|
363
|
+
|
|
364
|
+
On a backend serving one request at a time they do not -- they queue, so
|
|
365
|
+
fusion N=3 costs 3x the wall clock of a single call for the same answer,
|
|
366
|
+
and the deliver run paying it has a fixed wall-clock budget to finish in.
|
|
367
|
+
|
|
368
|
+
Measured live (2026-08-20, ninfer --max-concurrency 1, qwen3.8-27b):
|
|
369
|
+
tool-carrying turns already bypass recipes via has_tools, but mission
|
|
370
|
+
PLANNING carries no tools -- so it ran under fusion N=3 and took ~20
|
|
371
|
+
minutes, 17% of a 120-minute run budget, before turn 1 existed.
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
def test_unknown_width_changes_nothing(self):
|
|
375
|
+
# Not every backend can be probed (ninfer serves no /slots), so silence
|
|
376
|
+
# is not evidence -- unknown width must leave behaviour identical.
|
|
377
|
+
self.assertEqual(ce.select_recipe(body(), S(recipe="fusion"), False), "fusion")
|
|
378
|
+
|
|
379
|
+
def test_single_slot_downgrades_explicit_fusion(self):
|
|
380
|
+
self.assertEqual(ce.select_recipe(body(), S(recipe="fusion", model_slots=1), False), "single")
|
|
381
|
+
|
|
382
|
+
def test_single_slot_downgrades_auto(self):
|
|
383
|
+
# auto can select fusion on its own; it must not be able to on one slot.
|
|
384
|
+
self.assertEqual(
|
|
385
|
+
ce.select_recipe(body("x" * 900), S(recipe="auto", model_slots=1), False), "single"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def test_single_slot_downgrades_other_multi_call_recipes(self):
|
|
389
|
+
for recipe in ("ratings", "remom"):
|
|
390
|
+
self.assertEqual(
|
|
391
|
+
ce.select_recipe(body(), S(recipe=recipe, model_slots=1), False), "single", recipe
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
def test_multi_slot_backend_keeps_fan_out(self):
|
|
395
|
+
# The cost being avoided is serialization. With real parallelism there
|
|
396
|
+
# is nothing to avoid.
|
|
397
|
+
self.assertEqual(ce.select_recipe(body(), S(recipe="fusion", model_slots=4), False), "fusion")
|
|
398
|
+
|
|
399
|
+
def test_operator_can_force_fan_out_on_one_slot(self):
|
|
400
|
+
self.assertEqual(
|
|
401
|
+
ce.select_recipe(body(), S(recipe="fusion", model_slots=1, force_multi_call=True), False),
|
|
402
|
+
"fusion",
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
def test_single_call_recipe_is_left_alone(self):
|
|
406
|
+
# `confidence` issues one generation and only escalates conditionally;
|
|
407
|
+
# downgrading it would remove quality for no latency win.
|
|
408
|
+
self.assertEqual(
|
|
409
|
+
ce.select_recipe(body(), S(recipe="confidence", model_slots=1), False), "confidence"
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
def test_zero_slots_counts_as_single(self):
|
|
413
|
+
self.assertEqual(ce.select_recipe(body(), S(recipe="fusion", model_slots=0), False), "single")
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class SlotWidthResolutionTest(unittest.TestCase):
|
|
417
|
+
"""Width comes from the environment ONCE, at Settings construction."""
|
|
418
|
+
|
|
419
|
+
def setUp(self):
|
|
420
|
+
self._saved = {k: os.environ.get(k) for k in ("UAP_MODEL_SLOTS", "PROXY_MODEL_SLOTS")}
|
|
421
|
+
for k in self._saved:
|
|
422
|
+
os.environ.pop(k, None)
|
|
423
|
+
|
|
424
|
+
def tearDown(self):
|
|
425
|
+
for k, v in self._saved.items():
|
|
426
|
+
if v is None:
|
|
427
|
+
os.environ.pop(k, None)
|
|
428
|
+
else:
|
|
429
|
+
os.environ[k] = v
|
|
430
|
+
|
|
431
|
+
def test_absent_is_unknown(self):
|
|
432
|
+
self.assertIsNone(ce.resolve_model_slots())
|
|
433
|
+
|
|
434
|
+
def test_reads_the_shared_variable(self):
|
|
435
|
+
os.environ["UAP_MODEL_SLOTS"] = "1"
|
|
436
|
+
self.assertEqual(ce.resolve_model_slots(), 1)
|
|
437
|
+
|
|
438
|
+
def test_proxy_local_alias_is_honoured(self):
|
|
439
|
+
os.environ["PROXY_MODEL_SLOTS"] = "2"
|
|
440
|
+
self.assertEqual(ce.resolve_model_slots(), 2)
|
|
441
|
+
|
|
442
|
+
def test_unparseable_width_is_unknown_not_single(self):
|
|
443
|
+
# A typo must not silently disable fan-out everywhere.
|
|
444
|
+
os.environ["UAP_MODEL_SLOTS"] = "lots"
|
|
445
|
+
self.assertIsNone(ce.resolve_model_slots())
|
|
446
|
+
|
|
447
|
+
def test_ambient_one_slot_env_does_not_move_an_explicit_setting(self):
|
|
448
|
+
# THE isolation property. proxy.env now carries UAP_MODEL_SLOTS on a
|
|
449
|
+
# one-slot box and the proxy env loader setdefaults it into every
|
|
450
|
+
# subprocess; when the selector read process env directly, that ambient
|
|
451
|
+
# value silently failed 15 unrelated tests in this file.
|
|
452
|
+
os.environ["UAP_MODEL_SLOTS"] = "1"
|
|
453
|
+
self.assertEqual(ce.select_recipe(body(), S(recipe="fusion"), False), "fusion")
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class SlotDowngradeSkipsGenerationsTest(unittest.TestCase):
|
|
457
|
+
"""The cost being avoided is upstream GENERATIONS, so assert on the calls."""
|
|
458
|
+
|
|
459
|
+
def test_one_slot_backend_issues_no_extra_generations(self):
|
|
460
|
+
primary = {"content": [{"type": "text", "text": "answer"}]}
|
|
461
|
+
calls = []
|
|
462
|
+
|
|
463
|
+
async def call_primary(**kw):
|
|
464
|
+
calls.append(kw)
|
|
465
|
+
return primary
|
|
466
|
+
|
|
467
|
+
async def call_judge(**kw):
|
|
468
|
+
raise AssertionError("judge must not be called on a downgraded turn")
|
|
469
|
+
|
|
470
|
+
out = run(
|
|
471
|
+
ce.apply_recipe(
|
|
472
|
+
primary, body(), {"model": "qwen"},
|
|
473
|
+
S(recipe="fusion", model_slots=1),
|
|
474
|
+
False, call_primary, call_judge,
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
self.assertEqual(len(calls), 0)
|
|
478
|
+
self.assertIs(out, primary)
|
|
479
|
+
|
|
480
|
+
def test_off_values_do_not_force_fan_out(self):
|
|
481
|
+
# The escape hatch is a negative-set membership test; a refactor to
|
|
482
|
+
# bool(os.environ.get(...)) would invert it and only "1" is otherwise covered.
|
|
483
|
+
for raw in ("0", "false", "off", "no", ""):
|
|
484
|
+
with self.subTest(raw=raw):
|
|
485
|
+
os.environ["PROXY_FORCE_MULTI_CALL"] = raw
|
|
486
|
+
try:
|
|
487
|
+
self.assertFalse(ce.Settings.from_env().force_multi_call)
|
|
488
|
+
finally:
|
|
489
|
+
os.environ.pop("PROXY_FORCE_MULTI_CALL", None)
|
|
490
|
+
|
|
491
|
+
|
|
354
492
|
if __name__ == "__main__":
|
|
355
493
|
unittest.main()
|