@miller-tech/uap 1.210.2 → 1.210.3

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.
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+
6
+ # Fail-safe passthrough default: when ANTHROPIC_PASSTHROUGH_MODELS is unset OR
7
+ # EMPTY, default it to __local_only__ (no api.anthropic.com forwarding) rather
8
+ # than the code's empty=forward-cloud default. Set here in the ExecStart script
9
+ # so it wins over systemd's EnvironmentFile (which overrides Environment=, so a
10
+ # systemd Environment= pin cannot hold) and over the env file drifting back to
11
+ # empty via `uap model routing use`/setup. An operator who genuinely wants cloud
12
+ # passthrough sets an explicit non-empty value (a comma list of claude- ids),
13
+ # which is preserved. This is the durable enforcement of the local-only policy.
14
+ export ANTHROPIC_PASSTHROUGH_MODELS="${ANTHROPIC_PASSTHROUGH_MODELS:-__local_only__}"
15
+
16
+ export PROXY_PORT="${PROXY_PORT:-4000}"
17
+ export LLAMA_CPP_BASE="${LLAMA_CPP_BASE:-http://127.0.0.1:8080/v1}"
18
+ export PROXY_LOG_LEVEL="${PROXY_LOG_LEVEL:-INFO}"
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # Upstream resolution. LLAMA_CPP_BASE above is a PIN, and a pin goes stale:
22
+ # Unsloth Studio restarts its bundled llama-server on a new random port each
23
+ # launch (:50047 -> :34407 -> :59879 observed), after which every local request
24
+ # 529s until the env file is hand-edited — and that file is self-protect'd, so
25
+ # the agent cannot repair it. Resolve against reality instead: the pin is kept
26
+ # whenever it answers /health, and only a proven-dead pin falls through to
27
+ # discovering the live llama-server. Set UAP_LLAMA_UPSTREAM_AUTODISCOVER=off to
28
+ # pin hard. Must run BEFORE the context-window probe below, which reads
29
+ # LLAMA_CPP_BASE.
30
+ # ---------------------------------------------------------------------------
31
+ # Sourced defensively. Under `set -e` an unreadable lib would abort the script
32
+ # BEFORE exec, and the unit's Restart=always/RestartSec=3 would then respawn it
33
+ # every three seconds with no proxy at all — strictly worse than the stale pin
34
+ # this resolves. scripts/lib is not in package.json `files`, so an installed
35
+ # deployment can legitimately lack it. Degrade to the pin instead.
36
+ _upstream_lib="${ROOT_DIR}/scripts/lib/llama-upstream.sh"
37
+ if [ -r "$_upstream_lib" ]; then
38
+ # shellcheck source=lib/llama-upstream.sh
39
+ . "$_upstream_lib"
40
+ else
41
+ echo "[proxy-startup] WARNING: ${_upstream_lib} missing; using pinned upstream without discovery" >&2
42
+ llama_upstream_resolve() { printf '%s' "${1:-}"; }
43
+ llama_upstream_root() { local b="${1:-}"; b="${b%/}"; printf '%s' "${b%/v1}"; }
44
+ fi
45
+ _resolved_base="$(llama_upstream_resolve "$LLAMA_CPP_BASE")"
46
+ # An empty result would export LLAMA_CPP_BASE="" and degrade every upstream URL
47
+ # to a bare "/chat/completions"; keep the pin instead.
48
+ [ -n "$_resolved_base" ] || _resolved_base="$LLAMA_CPP_BASE"
49
+ if [ "$_resolved_base" != "$LLAMA_CPP_BASE" ]; then
50
+ echo "[proxy-startup] pinned upstream ${LLAMA_CPP_BASE} is unreachable; using discovered ${_resolved_base}"
51
+ export LLAMA_CPP_BASE="$_resolved_base"
52
+ else
53
+ echo "[proxy-startup] upstream: ${LLAMA_CPP_BASE}"
54
+ fi
55
+
56
+ export PROXY_LOOP_BREAKER="${PROXY_LOOP_BREAKER:-on}"
57
+ export PROXY_LOOP_WINDOW="${PROXY_LOOP_WINDOW:-6}"
58
+ export PROXY_LOOP_REPEAT_THRESHOLD="${PROXY_LOOP_REPEAT_THRESHOLD:-8}"
59
+ export PROXY_FORCED_THRESHOLD="${PROXY_FORCED_THRESHOLD:-15}"
60
+ export PROXY_NO_PROGRESS_THRESHOLD="${PROXY_NO_PROGRESS_THRESHOLD:-4}"
61
+ export PROXY_CONTEXT_RELEASE_THRESHOLD="${PROXY_CONTEXT_RELEASE_THRESHOLD:-0.90}"
62
+ export PROXY_GUARDRAIL_RETRY="${PROXY_GUARDRAIL_RETRY:-on}"
63
+ export PROXY_SESSION_TTL_SECS="${PROXY_SESSION_TTL_SECS:-7200}"
64
+
65
+ # Cross-session slot save/restore (UAP PR #179). Default ON: with
66
+ # llama-server on --parallel 1 (a single slot), N agentic sessions
67
+ # multiplexing the slot each evict the prior session's KV cache, forcing
68
+ # 60-96s full prompt reprocesses (~17% of requests). The proxy saves the
69
+ # outgoing session's slot state and restores the incoming session's on a
70
+ # switch. PROXY_SLOT_SAVE_DIR must match llama-server's --slot-save-path
71
+ # (run-llama-server-continuity.sh LLAMA_SLOT_SAVE_PATH). Set
72
+ # PROXY_SLOT_SAVE_RESTORE=off to disable.
73
+ export PROXY_SLOT_SAVE_RESTORE="${PROXY_SLOT_SAVE_RESTORE:-on}"
74
+ export PROXY_SLOT_SAVE_DIR="${PROXY_SLOT_SAVE_DIR:-${HOME}/.cache/uap/llama-slots}"
75
+ export PROXY_SLOT_CACHE_MAX_FILES="${PROXY_SLOT_CACHE_MAX_FILES:-12}"
76
+
77
+ export PROXY_TOOL_CALL_GRAMMAR="${PROXY_TOOL_CALL_GRAMMAR:-on}"
78
+ export PROXY_TOOL_CALL_GRAMMAR_REQUIRED_ONLY="${PROXY_TOOL_CALL_GRAMMAR_REQUIRED_ONLY:-on}"
79
+ export PROXY_TOOL_CALL_GRAMMAR_PATH="${PROXY_TOOL_CALL_GRAMMAR_PATH:-${ROOT_DIR}/tools/agents/config/tool-call.gbnf}"
80
+
81
+ # Structured thinking grammar (opt-in). When on, non-tool reasoning turns
82
+ # are constrained to emit a compact <think> Q/M/K/R/V header before output.
83
+ export PROXY_THINKING_GRAMMAR="${PROXY_THINKING_GRAMMAR:-off}"
84
+ export PROXY_THINKING_GRAMMAR_PATH="${PROXY_THINKING_GRAMMAR_PATH:-${ROOT_DIR}/tools/agents/config/thinking.gbnf}"
85
+
86
+ # ---------------------------------------------------------------------------
87
+ # Auto-detect context window from upstream llama-server /slots endpoint.
88
+ # Waits up to 60s for the server to be ready. Falls back to env var or 131072.
89
+ # This ensures the proxy always matches the server's actual per-slot context,
90
+ # even after server restarts with different --ctx-size / --parallel settings.
91
+ # ---------------------------------------------------------------------------
92
+ if [ "${PROXY_CONTEXT_WINDOW:-0}" = "0" ]; then
93
+ # Was an inline ${LLAMA_CPP_BASE/\/v1/} substitution, which strips the FIRST
94
+ # "/v1" anywhere in the string; llama_upstream_root strips only a trailing
95
+ # one. Same job, one rule.
96
+ SLOTS_URL="$(llama_upstream_root "$LLAMA_CPP_BASE")/slots"
97
+ echo "[proxy-startup] Detecting context window from ${SLOTS_URL}..."
98
+ for i in $(seq 1 30); do
99
+ CTX=$(curl -sf --max-time 2 -- "$SLOTS_URL" 2>/dev/null \
100
+ | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['n_ctx'])" 2>/dev/null)
101
+ if [ -n "$CTX" ] && [ "$CTX" -gt 0 ]; then
102
+ export PROXY_CONTEXT_WINDOW="$CTX"
103
+ echo "[proxy-startup] Auto-detected context window: ${CTX} tokens"
104
+ break
105
+ fi
106
+ sleep 2
107
+ done
108
+ if [ "${PROXY_CONTEXT_WINDOW:-0}" = "0" ]; then
109
+ export PROXY_CONTEXT_WINDOW=131072
110
+ echo "[proxy-startup] WARNING: Could not detect context, using default: 131072"
111
+ fi
112
+ fi
113
+
114
+ cd "$ROOT_DIR"
115
+
116
+ # Startup resolution alone still strands a LONG-LIVED proxy: llama can move
117
+ # ports hours after the proxy came up. Watch it in the background and stop the
118
+ # proxy once the upstream has demonstrably moved, so the supervisor restarts it
119
+ # through resolution above. $$ is the proxy's PID after the exec below, and the
120
+ # watcher dies with it via the unit's control group.
121
+ #
122
+ # SUPERVISED ONLY. src/cli/proxy.ts also launches this script as a detached,
123
+ # unsupervised `spawn(...)` when the systemd unit is not installed (fresh
124
+ # installs, UAP_PROXY_NO_SYSTEMD=1, containers, bench hosts). There, stopping
125
+ # the proxy is not a restart — it is the end of the proxy, which is strictly
126
+ # worse than pointing at a dead upstream, and on a bench host it would score as
127
+ # model failure rather than infrastructure failure. systemd sets INVOCATION_ID,
128
+ # so use it as the supervisor probe. UAP_LLAMA_UPSTREAM_WATCH=on forces the
129
+ # watcher on (for another supervisor), =off disables it everywhere.
130
+ _watch="${UAP_LLAMA_UPSTREAM_WATCH:-auto}"
131
+ if command -v llama_upstream_watch >/dev/null 2>&1 &&
132
+ { [ "$_watch" = "on" ] || { [ "$_watch" = "auto" ] && [ -n "${INVOCATION_ID:-}" ]; }; }; then
133
+ llama_upstream_watch "$LLAMA_CPP_BASE" "$$" &
134
+ fi
135
+
136
+ exec python3 tools/agents/scripts/anthropic_proxy.py