@miller-tech/uap 1.220.11 → 1.220.12

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.
@@ -41,6 +41,15 @@
41
41
  # =====================================================================
42
42
  LLAMA_BIN=/home/cogtek/llama.cpp/.worktrees/latest-master/build/bin/llama-server
43
43
  LLAMA_MODEL=/home/cogtek/Downloads/gemma-4-26B-A4B-it-UD-IQ4_XS.gguf
44
+ # Model id advertised to API clients (llama-server --alias). Set it EXPLICITLY
45
+ # here: the script's fallback derives a name from the GGUF filename, which is a
46
+ # name rather than a path but is not the name client configs are written
47
+ # against ("Qwen3.8-27B-UD-IQ4_XS" vs "Qwen3.8-27B"), so the proxy would still
48
+ # rewrite the model on every request.
49
+ # ORDER IS NOT PRESERVED: llama.cpp stores aliases in a std::set and reports
50
+ # *begin() as the model id, so the ASCII-FIRST entry becomes the primary id.
51
+ # Keep the id clients actually use sorting first if you add more.
52
+ LLAMA_ALIAS=Gemma4-26B-A4B
44
53
  LLAMA_DRAFT_MODEL=/home/cogtek/Downloads/mtp-gemma-4-26B-A4B-it-Q8_0.gguf
45
54
 
46
55
  # Vision projector MUST be pinned. The launch script's auto-discovery falls
@@ -23,6 +23,15 @@
23
23
  # =====================================================================
24
24
  LLAMA_BIN=/home/cogtek/llama.cpp/.worktrees/latest-master/build/bin/llama-server
25
25
  LLAMA_MODEL=/home/cogtek/Downloads/Qwen3.6-35B-A3B-UD-IQ4_XS.gguf
26
+ # Model id advertised to API clients (llama-server --alias). Set it EXPLICITLY
27
+ # here: the script's fallback derives a name from the GGUF filename, which is a
28
+ # name rather than a path but is not the name client configs are written
29
+ # against ("Qwen3.8-27B-UD-IQ4_XS" vs "Qwen3.8-27B"), so the proxy would still
30
+ # rewrite the model on every request.
31
+ # ORDER IS NOT PRESERVED: llama.cpp stores aliases in a std::set and reports
32
+ # *begin() as the model id, so the ASCII-FIRST entry becomes the primary id.
33
+ # Keep the id clients actually use sorting first if you add more.
34
+ LLAMA_ALIAS=Qwen3.6-35B-A3B
26
35
  LLAMA_MMPROJ=/home/cogtek/Downloads/mmproj-F16.gguf
27
36
 
28
37
  LLAMA_HOST=0.0.0.0
@@ -68,6 +68,15 @@
68
68
  # =====================================================================
69
69
  LLAMA_BIN=/home/cogtek/llama.cpp/.worktrees/dflash2-trial/build-cuda/bin/llama-server
70
70
  LLAMA_MODEL=/home/cogtek/Downloads/Qwen3.8-27B-UD-IQ4_XS.gguf
71
+ # Model id advertised to API clients (llama-server --alias). Set it EXPLICITLY
72
+ # here: the script's fallback derives a name from the GGUF filename, which is a
73
+ # name rather than a path but is not the name client configs are written
74
+ # against ("Qwen3.8-27B-UD-IQ4_XS" vs "Qwen3.8-27B"), so the proxy would still
75
+ # rewrite the model on every request.
76
+ # ORDER IS NOT PRESERVED: llama.cpp stores aliases in a std::set and reports
77
+ # *begin() as the model id, so the ASCII-FIRST entry becomes the primary id.
78
+ # Keep the id clients actually use sorting first if you add more.
79
+ LLAMA_ALIAS=Qwen3.8-27B
71
80
  # CONFIRMED INCOMPATIBLE 2026-08-20: mmproj-BF16.gguf crashed the server on
72
81
  # load -- "mismatch between text model (n_embd = 5120) and mmproj
73
82
  # (n_embd = 2048)". It was built for a different, smaller model's vision
@@ -36,6 +36,15 @@
36
36
  # =====================================================================
37
37
  LLAMA_BIN=/home/cogtek/llama.cpp/.worktrees/dflash-mtp-upgrade/build-cuda/bin/llama-server
38
38
  LLAMA_MODEL=/home/cogtek/Downloads/Qwen3.8-27B-UD-IQ4_XS.gguf
39
+ # Model id advertised to API clients (llama-server --alias). Set it EXPLICITLY
40
+ # here: the script's fallback derives a name from the GGUF filename, which is a
41
+ # name rather than a path but is not the name client configs are written
42
+ # against ("Qwen3.8-27B-UD-IQ4_XS" vs "Qwen3.8-27B"), so the proxy would still
43
+ # rewrite the model on every request.
44
+ # ORDER IS NOT PRESERVED: llama.cpp stores aliases in a std::set and reports
45
+ # *begin() as the model id, so the ASCII-FIRST entry becomes the primary id.
46
+ # Keep the id clients actually use sorting first if you add more.
47
+ LLAMA_ALIAS=Qwen3.8-27B
39
48
  # CONFIRMED INCOMPATIBLE 2026-08-20: mmproj-BF16.gguf crashed the server on
40
49
  # load -- "mismatch between text model (n_embd = 5120) and mmproj
41
50
  # (n_embd = 2048)". It was built for a different, smaller model's vision
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.220.11",
3
+ "version": "1.220.12",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "start": "node dist/bin/cli.js",
22
22
  "test": "vitest",
23
23
  "test:ci": "vitest run",
24
- "test:enforcers": "UAP_PROXY_ENV_AUTOLOAD=0 python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_conditional_destructive_verbs tools.agents.tests.test_live_deliver_kill tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_schema_diff_inline tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_gate_evidence tools.agents.tests.test_repeat_call_guard tools.agents.tests.test_repeat_guard tools.agents.tests.test_gate_integrity tools.agents.tests.test_gate_failclosed_indirection tools.agents.tests.test_gate_failclosed_schema_diff tools.agents.tests.test_rtk_wrap tools.agents.tests.test_expert_review_pr_scope tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_write_complexity tools.agents.tests.test_fastpath_config tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_stuck_break_hard tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_enforcer_suite_coverage tools.agents.tests.test_validate_plan_gate tools.agents.tests.test_validate_plan_inside_project tools.agents.tests.test_anthropic_proxy_streaming tools.agents.tests.test_non_stream_resp_log tools.agents.tests.test_delivery_enforcement_worktree tools.agents.tests.test_output_token_ceilings tools.agents.tests.test_tool_narrowing_core tools.agents.tests.test_models_context_window tools.agents.tests.test_thinking_template_kwargs tools.agents.tests.test_cycle_break_wait_poll",
24
+ "test:enforcers": "UAP_PROXY_ENV_AUTOLOAD=0 python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_conditional_destructive_verbs tools.agents.tests.test_live_deliver_kill tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_schema_diff_inline tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_gate_evidence tools.agents.tests.test_repeat_call_guard tools.agents.tests.test_repeat_guard tools.agents.tests.test_gate_integrity tools.agents.tests.test_gate_failclosed_indirection tools.agents.tests.test_gate_failclosed_schema_diff tools.agents.tests.test_rtk_wrap tools.agents.tests.test_expert_review_pr_scope tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_write_complexity tools.agents.tests.test_fastpath_config tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_stuck_break_hard tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_enforcer_suite_coverage tools.agents.tests.test_validate_plan_gate tools.agents.tests.test_validate_plan_inside_project tools.agents.tests.test_anthropic_proxy_streaming tools.agents.tests.test_non_stream_resp_log tools.agents.tests.test_delivery_enforcement_worktree tools.agents.tests.test_output_token_ceilings tools.agents.tests.test_tool_narrowing_core tools.agents.tests.test_models_context_window tools.agents.tests.test_thinking_template_kwargs tools.agents.tests.test_cycle_break_wait_poll tools.agents.tests.test_upstream_model_aliases",
25
25
  "test:coverage": "vitest --coverage",
26
26
  "bench": "vitest --config vitest.bench.config.ts",
27
27
  "lint": "eslint src --ext .ts",
@@ -1342,7 +1342,20 @@ async def _upstream_model_ids_cached() -> list[str] | None:
1342
1342
  if r.status_code != 200:
1343
1343
  return None
1344
1344
  data = (r.json() or {}).get("data") or []
1345
- ids = [str(m["id"]) for m in data if isinstance(m, dict) and m.get("id")]
1345
+ # Aliases count as served ids. llama-server reports ONE primary `id`
1346
+ # (the ASCII-first entry of a std::set) plus an `aliases` array, so a
1347
+ # config naming any other registered alias looked unserved and got
1348
+ # rewritten on every request -- which is most of what --alias was added
1349
+ # to stop. Reading only `id` made the flag half-useless.
1350
+ ids: list[str] = []
1351
+ for m in data:
1352
+ if not isinstance(m, dict):
1353
+ continue
1354
+ if m.get("id"):
1355
+ ids.append(str(m["id"]))
1356
+ for alias in m.get("aliases") or []:
1357
+ if alias and str(alias) not in ids:
1358
+ ids.append(str(alias))
1346
1359
  if ids:
1347
1360
  _upstream_model_ids = ids
1348
1361
  return ids or None
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ """An advertised alias is a servable model id.
3
+
4
+ llama-server registers aliases in a std::set and reports ONE primary `id` --
5
+ `*begin()`, i.e. the ASCII-first entry -- alongside an `aliases` array carrying
6
+ all of them. The proxy read only `id`, so every client configured with any other
7
+ registered alias looked unservable and had its model rewritten on EVERY request
8
+ (MODEL REWRITE, 6 in a 3h window on 2026-08-25).
9
+
10
+ That made --alias half-useless for the thing it was added to fix: naming legacy
11
+ ids alongside a new one so an older client config keeps resolving untouched.
12
+ """
13
+
14
+ import asyncio
15
+ import importlib.util
16
+ import unittest
17
+ from pathlib import Path
18
+
19
+
20
+ def _load_proxy_module():
21
+ proxy_path = Path(__file__).resolve().parents[1] / "scripts" / "anthropic_proxy.py"
22
+ spec = importlib.util.spec_from_file_location("anthropic_proxy", proxy_path)
23
+ assert spec is not None and spec.loader is not None
24
+ module = importlib.util.module_from_spec(spec)
25
+ spec.loader.exec_module(module)
26
+ return module
27
+
28
+
29
+ proxy = _load_proxy_module()
30
+
31
+
32
+ class _FakeResponse:
33
+ def __init__(self, payload, status_code=200):
34
+ self._payload = payload
35
+ self.status_code = status_code
36
+ self.text = str(payload)
37
+
38
+ def json(self):
39
+ return self._payload
40
+
41
+
42
+ class _FakeClient:
43
+ """Stands in for the httpx client; records nothing, just answers /models."""
44
+
45
+ def __init__(self, payload, status_code=200):
46
+ self._response = _FakeResponse(payload, status_code)
47
+
48
+ async def get(self, _url, timeout=None): # noqa: ARG002 - signature parity
49
+ return self._response
50
+
51
+
52
+ class UpstreamModelAliasTests(unittest.TestCase):
53
+ def setUp(self):
54
+ # The result is cached in a module global for the process lifetime.
55
+ self._saved_client = proxy.http_client
56
+ proxy._upstream_model_ids = None
57
+
58
+ def tearDown(self):
59
+ proxy.http_client = self._saved_client
60
+ proxy._upstream_model_ids = None
61
+
62
+ def _ids(self, payload, status_code=200):
63
+ proxy.http_client = _FakeClient(payload, status_code)
64
+ return asyncio.run(proxy._upstream_model_ids_cached())
65
+
66
+ def test_aliases_are_reported_as_served_ids(self):
67
+ ids = self._ids(
68
+ {
69
+ "data": [
70
+ {
71
+ "id": "Qwen3.8-27B",
72
+ "aliases": ["Qwen3.8-27B", "qwen36-35b-a3b-iq4xs", "qwen35-a3b-iq4xs"],
73
+ }
74
+ ]
75
+ }
76
+ )
77
+ # The legacy ids are exactly the ones that were being rewritten.
78
+ self.assertIn("qwen36-35b-a3b-iq4xs", ids)
79
+ self.assertIn("qwen35-a3b-iq4xs", ids)
80
+ self.assertIn("Qwen3.8-27B", ids)
81
+
82
+ def test_the_primary_id_stays_first(self):
83
+ # Callers pick ids[0] as the rewrite target, so the primary must lead
84
+ # even though it also appears in the aliases array.
85
+ ids = self._ids({"data": [{"id": "Primary", "aliases": ["Primary", "Alt"]}]})
86
+ self.assertEqual(ids[0], "Primary")
87
+
88
+ def test_the_primary_id_is_not_duplicated_by_its_own_alias_entry(self):
89
+ # llama-server lists the primary inside `aliases` too.
90
+ ids = self._ids({"data": [{"id": "Same", "aliases": ["Same"]}]})
91
+ self.assertEqual(ids, ["Same"])
92
+
93
+ def test_a_payload_with_no_aliases_key_still_works(self):
94
+ # Older llama-server builds, and any other OpenAI-compatible upstream.
95
+ ids = self._ids({"data": [{"id": "OnlyId"}]})
96
+ self.assertEqual(ids, ["OnlyId"])
97
+
98
+ def test_junk_entries_are_skipped_rather_than_raising(self):
99
+ # Discovery must never take the proxy down.
100
+ ids = self._ids(
101
+ {
102
+ "data": [
103
+ "not-a-dict",
104
+ {"no_id": True},
105
+ {"id": "Good", "aliases": [None, "", "AlsoGood"]},
106
+ ]
107
+ }
108
+ )
109
+ self.assertEqual(ids, ["Good", "AlsoGood"])
110
+
111
+ def test_a_non_200_yields_no_ids(self):
112
+ self.assertIsNone(self._ids({"data": [{"id": "x"}]}, status_code=503))
113
+
114
+
115
+ if __name__ == "__main__":
116
+ unittest.main()