@miller-tech/uap 1.46.4 → 1.46.7
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/docs/INDEX.md
CHANGED
|
@@ -18,8 +18,8 @@ New here? Start with the [project README](../README.md), then [Getting Started](
|
|
|
18
18
|
|
|
19
19
|
| Doc | What it covers |
|
|
20
20
|
|---|---|
|
|
21
|
-
| [**What UAP Does Automatically**](guides/
|
|
22
|
-
| [**`uap deliver`**](guides/DELIVER.md) | The delivery harness — convergence loop to verified completion ⭐ |
|
|
21
|
+
| [**What UAP Does Automatically**](guides/AUTOMATIC_FEATURES.md) | Every feature in benefit / when-it-kicks-in terms — install once, it all self-applies ⭐ |
|
|
22
|
+
| [**`uap deliver`**](guides/DELIVER.md) | The delivery harness — verified changes via convergence loop ⭐ |ess — convergence loop to verified completion ⭐ |
|
|
23
23
|
| [Memory](guides/MEMORY.md) | The 4-tier memory system, write-gates, semantic recall |
|
|
24
24
|
| [MCP Router](guides/MCP_ROUTER.md) | Token-optimizing tool proxy + FTS5 output compression |
|
|
25
25
|
| [Worktree Workflow](guides/WORKTREE_WORKFLOW.md) | Branch-per-feature isolation, auto-PR, enforcement |
|
package/docs/guides/AUTOMATIC.md
CHANGED
|
@@ -1,92 +1,286 @@
|
|
|
1
|
-
# What UAP Does
|
|
1
|
+
# What UAP Does Automatically
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
> as you code.** You don't call commands or remember protocols. UAP watches the
|
|
5
|
-
> coding agent's lifecycle (session start, every prompt, every tool call, every
|
|
6
|
-
> stop) and injects the right help or enforces the right guardrail *at the moment
|
|
7
|
-
> it's needed*.
|
|
3
|
+
> **Install once. Every feature kicks in automatically.**
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
UAP is not a set of manual steps you orchestrate. It is a **policy-and-resolver
|
|
6
|
+
layer** that sits between your coding agent (Claude Code, Opencode, Cursor,
|
|
7
|
+
Windsurf, Codex, etc.) and the model you use. Every feature below activates
|
|
8
|
+
**automatically** based on what the agent is doing — no config changes, no
|
|
9
|
+
manual triggers, no prompts to remember.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
When you start a coding session, UAP's hooks (installed by `uap setup`)
|
|
16
|
+
intercept every prompt the agent sends to the model. The **Reactor**
|
|
17
|
+
(`CapabilityRouter` + `PatternRouter`) evaluates the prompt in
|
|
18
|
+
real-time and, when appropriate, **injects** context, skills, or tool calls
|
|
19
|
+
into the agent's next turn. You never notice it happening — the agent just
|
|
20
|
+
produces better results.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
You → hook → UAP Reactor (auto-inject) → model → agent → better output
|
|
12
24
|
```
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
The confidence gate controls injection:
|
|
27
|
+
|
|
28
|
+
| Confidence | Behavior |
|
|
29
|
+
|---|---|
|
|
30
|
+
| ≥ 0.30 | Inject context/skills/experts into the prompt |
|
|
31
|
+
| ≥ 0.80 | Auto-spawn subagent with `uap deliver` for heavy lifting |
|
|
32
|
+
| < 0.30 | Pass through unchanged — zero overhead |
|
|
18
33
|
|
|
19
34
|
---
|
|
20
35
|
|
|
21
|
-
##
|
|
36
|
+
## Every feature, when it kicks in
|
|
37
|
+
|
|
38
|
+
### Reactor — Expert, Skill & Pattern Injection
|
|
22
39
|
|
|
23
|
-
|
|
40
|
+
**Benefit:** Your model gets expert-level context for every prompt without you
|
|
41
|
+
having to craft the perfect system prompt.
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
delivery, run a dangerous command). Each has an escape hatch for the rare
|
|
32
|
-
sanctioned exception.
|
|
43
|
+
**When it kicks in:** On every prompt the agent sends. The `CapabilityRouter`
|
|
44
|
+
matches the prompt against known droids (docker, infra, security, etc.) and
|
|
45
|
+
skills. The `PatternRouter` matches against a RAG-indexed library of proven
|
|
46
|
+
patterns. When confidence is ≥ 0.30, the relevant context is injected
|
|
47
|
+
automatically. When confidence is ≥ 0.80, a subagent is spawned to handle it
|
|
48
|
+
via `uap deliver`.
|
|
33
49
|
|
|
34
|
-
|
|
50
|
+
**You get:** Better code from any model — even small local models — because
|
|
51
|
+
they receive expert context they wouldn't otherwise have.
|
|
35
52
|
|
|
36
53
|
---
|
|
37
54
|
|
|
38
|
-
|
|
55
|
+
### Delivery Enforcement — `uap deliver` for Verified Output
|
|
39
56
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| **Reactor** (dynamic routing) | On every prompt, surfaces the expert droids, skills, and enforcement patterns relevant to *this* task, so the agent works like it already knows the domain. | Every substantive prompt (`UserPromptSubmit` / per-message). Confidence-gated — silent on "thanks"/"merge it", rich on "fix the auth race condition". |
|
|
43
|
-
| **Memory recall** | Pulls back the lessons, decisions, and gotchas you (or another agent) learned before, so mistakes aren't repeated and context survives across sessions. | Session start (recent + high-importance memories) and per-prompt semantic recall on the task text. |
|
|
44
|
-
| **Pattern RAG** | Injects battle-tested execution patterns (Output-Existence, Decoder-First, Round-Trip verify, …) mined from Terminal-Bench, so the agent uses the approach that actually passes. | Per-prompt, matched to the task; full set retrievable on demand via Qdrant. |
|
|
45
|
-
| **Expert droids** | Routes domain work (security, performance, data, testing, …) to a specialist persona instead of a generalist guess. | When the capability router matches the task's type/files — recommended automatically, with optional auto-spawn above a confidence threshold. |
|
|
46
|
-
| **Skills** | Surfaces the right *procedure* (git-forensics, compression, SQLite-WAL recovery, polyglot, …) for the task at hand. | Per-prompt match against the task; top-N surfaced. |
|
|
47
|
-
| **Model routing** | Picks the right model tier per step (plan with the strong model, execute with the fast one) instead of one model for everything. | On task classification, by complexity and role. |
|
|
57
|
+
**Benefit:** Your agent's output is actually correct before it touches your
|
|
58
|
+
code. No more "it compiled but the tests fail" or "it broke the build."
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
**When it kicks in:** Block-by-default. When the agent tries to edit source
|
|
61
|
+
files directly, the `delivery_enforcement` gate intercepts and routes the work
|
|
62
|
+
to `uap deliver` instead. The delivery harness runs a convergence loop: the
|
|
63
|
+
model iterates against real gates (build, typecheck, test) until everything
|
|
64
|
+
passes. Source-scoped: docs, configs, scripts, and tests are exempt (they
|
|
65
|
+
don't need delivery verification).
|
|
66
|
+
|
|
67
|
+
**Escape hatches:** `UAP_DELIVER_ACTIVE=1` to activate delivery for the
|
|
68
|
+
current session, `UAP_DELIVER_BYPASS=1` to skip enforcement,
|
|
69
|
+
`UAP_ENFORCE_DELIVERY=advisory` to downgrade from block to warning.
|
|
70
|
+
|
|
71
|
+
**You get:** Verified, working code from any model — including small local
|
|
72
|
+
models that would otherwise make mistakes.
|
|
51
73
|
|
|
52
74
|
---
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
### Memory — 4-Tier Auto-Recall
|
|
77
|
+
|
|
78
|
+
**Benefit:** Your coding agent remembers everything across sessions, projects,
|
|
79
|
+
and even different models. No more repeating yourself.
|
|
55
80
|
|
|
56
|
-
|
|
81
|
+
**When it kicks in:** On every prompt. The memory system has four tiers:
|
|
82
|
+
|
|
83
|
+
| Tier | What | How |
|
|
57
84
|
|---|---|---|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
| **Completion gates** | Won't let the agent declare "done" until build/type-check/tests actually pass and a version bump happened. | On `Stop` (end of turn). |
|
|
63
|
-
| **Coordination** | Detects when multiple agents would touch the same files and prevents them stepping on each other. | Session start (register) + work announcement before claiming a task. |
|
|
64
|
-
| **rtk token-optimization** | Rewrites heavy CLI output (git/docker/npm/…) into compact form so the agent burns far fewer tokens reading command output. | Every wrapped CLI command. |
|
|
65
|
-
| **Deploy batching** | Queues changes into conflict-free batched commits/deploys instead of racy one-off pushes. | On `uap deliver --deploy` success. |
|
|
85
|
+
| L1 — Semantic | Long-term project context | Nomic 768-dim embeddings, recalled via cosine similarity |
|
|
86
|
+
| L2 — Episodic | Past conversations & decisions | Stored as episodes, recalled by semantic similarity |
|
|
87
|
+
| L3 — Procedural | Commands, workflows, patterns | Stored as procedures, recalled when similar tasks arise |
|
|
88
|
+
| L4 — Declarative | Facts, configs, references | Direct key-value store, recalled by key lookup |
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
**You get:** Context-aware coding that improves over time. The agent remembers
|
|
91
|
+
your conventions, past decisions, and project architecture without you
|
|
92
|
+
re-explaining.
|
|
69
93
|
|
|
70
94
|
---
|
|
71
95
|
|
|
72
|
-
|
|
96
|
+
### Patterns RAG — Proven Solutions on Demand
|
|
97
|
+
|
|
98
|
+
**Benefit:** Your agent applies battle-tested patterns instead of reinventing
|
|
99
|
+
solutions. Every pattern is indexed and retrieved automatically.
|
|
100
|
+
|
|
101
|
+
**When it kicks in:** When the agent encounters a problem that matches a stored
|
|
102
|
+
pattern. The PatternRouter uses semantic search to find the best-matching
|
|
103
|
+
pattern from the library and injects it into the prompt.
|
|
104
|
+
|
|
105
|
+
**You get:** Consistent, proven solutions across all agents and sessions.
|
|
106
|
+
|
|
107
|
+
---
|
|
73
108
|
|
|
74
|
-
|
|
109
|
+
### Worktree Enforcement
|
|
110
|
+
|
|
111
|
+
**Benefit:** Your main branch stays clean. Every change happens in an isolated
|
|
112
|
+
worktree with proper version bumps and merge commits.
|
|
113
|
+
|
|
114
|
+
**When it kicks in:** On every file edit. The worktree gate verifies you're
|
|
115
|
+
working inside a valid worktree before allowing source file edits. Docs,
|
|
116
|
+
configs, and scripts are exempt from this gate.
|
|
117
|
+
|
|
118
|
+
**You get:** Clean git history, proper versioning, and no accidental commits
|
|
119
|
+
to main.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Policy Gates — Automated Safety
|
|
124
|
+
|
|
125
|
+
**Benefit:** Security, infrastructure parity, and delivery enforcement happen
|
|
126
|
+
automatically on every operation. No manual code reviews for common issues.
|
|
127
|
+
|
|
128
|
+
**When it kicks in:** On every tool use and CLI command:
|
|
129
|
+
|
|
130
|
+
| Gate | What it checks | When it fires |
|
|
75
131
|
|---|---|---|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
132
|
+
| rtk_wrap | Token optimization | Every CLI command |
|
|
133
|
+
| iac_parity | Infrastructure-as-Code safety | kubectl, helm, aws, gcloud, doctl |
|
|
134
|
+
| delivery_enforcement | Verified output | Every source file edit |
|
|
135
|
+
|
|
136
|
+
**You get:** Security and safety without manual intervention.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Droids & Skills — Specialized Expertise
|
|
141
|
+
|
|
142
|
+
**Benefit:** Your agent has access to specialized experts (docker, infra,
|
|
143
|
+
security, etc.) without you having to prompt for them.
|
|
144
|
+
|
|
145
|
+
**When it kicks in:** When the agent encounters work that matches a droid's
|
|
146
|
+
domain. The CapabilityRouter detects the match and injects the droid's context
|
|
147
|
+
automatically.
|
|
148
|
+
|
|
149
|
+
**You get:** Expert-level output in specialized domains from any model.
|
|
79
150
|
|
|
80
151
|
---
|
|
81
152
|
|
|
82
|
-
|
|
153
|
+
### Skills — Dynamic Capability Injection
|
|
154
|
+
|
|
155
|
+
**Benefit:** New capabilities are injected on-demand based on the prompt
|
|
156
|
+
content. No configuration needed.
|
|
157
|
+
|
|
158
|
+
**When it kicks in:** When the prompt matches a registered skill. Skills are
|
|
159
|
+
matched semantically and injected automatically.
|
|
160
|
+
|
|
161
|
+
**You get:** A coding agent that grows smarter over time as new skills are
|
|
162
|
+
added.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Coordination — Multi-Agent Orchestration
|
|
167
|
+
|
|
168
|
+
**Benefit:** Complex tasks are decomposed and executed automatically across
|
|
169
|
+
multiple agents with proper coordination.
|
|
170
|
+
|
|
171
|
+
**When it kicks in:** On complex prompts that benefit from multi-agent
|
|
172
|
+
parallelism. The coordinator decomposes the task, spawns parallel agents,
|
|
173
|
+
and merges results.
|
|
174
|
+
|
|
175
|
+
**You get:** Faster completion of complex tasks through parallel execution.
|
|
176
|
+
|
|
177
|
+
---
|
|
83
178
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
179
|
+
### MCP Router — 98% Token Reduction
|
|
180
|
+
|
|
181
|
+
**Benefit:** Massive token savings on Model Context Protocol calls. Instead of
|
|
182
|
+
sending full tool schemas on every turn, the router caches and compresses them.
|
|
183
|
+
|
|
184
|
+
**When it kicks in:** On every MCP tool call. The router intercepts the call,
|
|
185
|
+
looks up the cached schema, and sends only the minimal necessary context.
|
|
186
|
+
|
|
187
|
+
**You get:** 98% fewer tokens on MCP operations — dramatic cost and latency
|
|
188
|
+
reduction.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### Schema-Diff Gate — API Contract Validation
|
|
193
|
+
|
|
194
|
+
**Benefit:** Schema changes are validated automatically. No more breaking API
|
|
195
|
+
contracts silently.
|
|
196
|
+
|
|
197
|
+
**When it kicks in:** When the agent edits schema files or API contract
|
|
198
|
+
definitions. The gate diffs the before/after and validates compatibility.
|
|
199
|
+
|
|
200
|
+
**You get:** Safe API evolution without manual review of every schema change.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### Completion Gates — Verify "Done" is Actually Done
|
|
205
|
+
|
|
206
|
+
**Benefit:** When the agent claims it's done, the gates verify: tests pass,
|
|
207
|
+
build succeeds, lint is clean, version is bumped.
|
|
208
|
+
|
|
209
|
+
**When it kicks in:** When the agent claims a task is complete. The gates run
|
|
210
|
+
automated verification before accepting the result.
|
|
211
|
+
|
|
212
|
+
**You get:** Confidence that "done" means actually done.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### Deploy Batching — Atomic Multi-Change Deploys
|
|
217
|
+
|
|
218
|
+
**Benefit:** Multiple related changes are deployed atomically. No partial
|
|
219
|
+
deploys that leave the system in an inconsistent state.
|
|
220
|
+
|
|
221
|
+
**When it kicks in:** When the agent prepares deployable changes. Related
|
|
222
|
+
changes are batched together and deployed as a single atomic unit.
|
|
223
|
+
|
|
224
|
+
**You get:** Reliable deploys with zero downtime.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
### rtk — 60–90% Token Savings
|
|
229
|
+
|
|
230
|
+
**Benefit:** Massive token savings on every CLI command. rtk intercepts commands,
|
|
231
|
+
optimizes them, and proxies through a token-efficient layer.
|
|
232
|
+
|
|
233
|
+
**When it kicks in:** On every CLI command. rtk rewrites commands to use
|
|
234
|
+
optimized paths and caches results.
|
|
235
|
+
|
|
236
|
+
**You get:** Dramatically lower API costs and faster command execution.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### HALO — Human Oversight
|
|
241
|
+
|
|
242
|
+
**Benefit:** Critical operations require human approval before execution.
|
|
243
|
+
Automatic escalation when confidence is low.
|
|
244
|
+
|
|
245
|
+
**When it kicks in:** On critical operations (deployments, schema changes,
|
|
246
|
+
security-sensitive actions). HALO escalates to a human for approval.
|
|
247
|
+
|
|
248
|
+
**You get:** Safety for operations that matter, without slowing down routine
|
|
249
|
+
work.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Local Models — Punching Above Their Weight
|
|
254
|
+
|
|
255
|
+
**Benefit:** Small local models (like Qwen3.6-35B-A3B running on consumer
|
|
256
|
+
hardware) produce code quality that rivals much larger models.
|
|
257
|
+
|
|
258
|
+
**How:** UAP's `uap deliver` convergence loop, expert injection, and pattern
|
|
259
|
+
RAG compensate for the smaller model's limitations. The model iterates against
|
|
260
|
+
real gates (build, test, typecheck) until everything passes.
|
|
261
|
+
|
|
262
|
+
**See:** [Local Models Guide](./LOCAL_MODELS.md) for setup instructions and
|
|
263
|
+
VRAM-tiered configurations.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Quick Reference
|
|
268
|
+
|
|
269
|
+
| Feature | Benefit | Trigger |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| Reactor | Expert context for every prompt | Every prompt |
|
|
272
|
+
| Delivery Enforcement | Verified, working code | Every source edit |
|
|
273
|
+
| Memory | Remembers everything | Every prompt |
|
|
274
|
+
| Patterns RAG | Proven solutions | Pattern match |
|
|
275
|
+
| Worktree Enforcement | Clean git history | Every file edit |
|
|
276
|
+
| Policy Gates | Security & safety | Every tool/CLI |
|
|
277
|
+
| Droids & Skills | Specialized expertise | Domain match |
|
|
278
|
+
| Coordination | Parallel task execution | Complex tasks |
|
|
279
|
+
| MCP Router | 98% token reduction | Every MCP call |
|
|
280
|
+
| Schema-diff | API contract safety | Schema edits |
|
|
281
|
+
| Completion gates | Verify "done" is done | Agent claims done |
|
|
282
|
+
| Deploy batching | Atomic multi-change deploys | Deployable changes |
|
|
283
|
+
| rtk | 60–90% token savings | Every CLI command |
|
|
284
|
+
| HALO | Human oversight for critical ops | Critical actions |
|
|
89
285
|
|
|
90
|
-
|
|
91
|
-
[Droids & Skills](DROIDS_AND_SKILLS.md) · [Policies](POLICIES.md) ·
|
|
92
|
-
the [Reactor design](../design/UAP_REACTOR.md).
|
|
286
|
+
**Install UAP. Use your coding agent normally. Everything else is automatic.**
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# UAP Automatic Features — What Fires When
|
|
2
|
+
|
|
3
|
+
Install UAP (`npm i -g universal-agent-protocol`) and every feature below activates automatically. There are no flags to set, no config to edit. UAP observes your workflow and injects the right capability at the right time.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Per-Prompt Auto-Injection
|
|
8
|
+
|
|
9
|
+
### Reactor — Expert Skills, Patterns & Droids
|
|
10
|
+
**What it does:** Every time you submit a coding prompt, the Reactor evaluates the request against a router of 25+ droids (experts), skill libraries, and implementation patterns. Relevant ones are injected into the agent's context automatically.
|
|
11
|
+
|
|
12
|
+
**When it kicks in:**
|
|
13
|
+
- You ask to "fix the auth flow" → AuthDroid + relevant skill templates load
|
|
14
|
+
- You need a migration → MigrationDroid + schema-diff pattern activate
|
|
15
|
+
- You're refactoring → RefactorDroid + pattern-RAG suggestions appear
|
|
16
|
+
|
|
17
|
+
**Why it matters:** Your model gets domain-specific expertise injected per-prompt without you having to prompt for it. Confidence-gated: low-confidence matches are suggested; high-confidence matches (≥0.80) auto-spawn as subagents.
|
|
18
|
+
|
|
19
|
+
### Pattern RAG
|
|
20
|
+
**What it does:** Retrieves proven implementation patterns from the UAP pattern library based on your prompt's intent.
|
|
21
|
+
|
|
22
|
+
**When it kicks in:** Alongside Reactor evaluation — if your prompt matches a stored pattern (e.g., "add pagination", "implement rate limiting"), the pattern is injected as context.
|
|
23
|
+
|
|
24
|
+
**Why it matters:** Consistent, battle-tested implementations across every coding session. No reinventing the wheel.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Policy Gates (Block-by-Default)
|
|
29
|
+
|
|
30
|
+
### Delivery Enforcement
|
|
31
|
+
**What it does:** Prevents direct source-code edits by the model. Instead, routes changes through `uap deliver` — a convergence loop where the model iterates until real gates (build, typecheck, tests) pass.
|
|
32
|
+
|
|
33
|
+
**When it kicks in:** Any tool-use that touches source files (`.ts`, `.js`, `.py`, etc.). Docs, configs, scripts, tests, and `.worktrees/` are exempt (they don't need delivery).
|
|
34
|
+
|
|
35
|
+
**Why it matters:** Small models (Qwen3.6, Llama, etc.) frequently produce code that looks correct but doesn't compile. `uap deliver` catches this early — the model self-corrects through real compiler/test feedback until it actually works. Without it, broken code silently lands.
|
|
36
|
+
|
|
37
|
+
**Escape hatches:** `UAP_DELIVER_BYPASS=1` (one-shot), `UAP_DELIVER_ACTIVE=1` (session), `UAP_ENFORCE_DELIVERY=advisory` (warn-only).
|
|
38
|
+
|
|
39
|
+
### Schema-Diff Gate
|
|
40
|
+
**What it does:** Before any schema or API contract change is applied, generates and validates a diff to ensure backward compatibility.
|
|
41
|
+
|
|
42
|
+
**When it kicks in:** When the model proposes changes to TypeScript interfaces, OpenAPI specs, database schemas, or any contract file.
|
|
43
|
+
|
|
44
|
+
**Why it matters:** Prevents silent API breakage that would crash downstream consumers.
|
|
45
|
+
|
|
46
|
+
### Completion Gates
|
|
47
|
+
**What it does:** Before the model claims a task is "done," it must pass: build succeeds, tests pass, type-check clean, version bumped, self-reviewed.
|
|
48
|
+
|
|
49
|
+
**When it kicks in:** Automatically when the model attempts to mark a task complete.
|
|
50
|
+
|
|
51
|
+
**Why it matters:** Eliminates "it works on my machine" — every change is verified against the full test + build pipeline before being considered done.
|
|
52
|
+
|
|
53
|
+
### Worktree Enforcement
|
|
54
|
+
**What it does:** Requires all source edits to happen inside isolated worktrees. Prevents accidental commits to the wrong branch.
|
|
55
|
+
|
|
56
|
+
**When it kicks in:** Any attempt to edit source files outside a worktree.
|
|
57
|
+
|
|
58
|
+
**Why it matters:** Clean git history, isolated feature branches, no accidental merges of incomplete work.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Model Uplift
|
|
63
|
+
|
|
64
|
+
### `uap deliver` — Convergence Loop
|
|
65
|
+
**What it does:** When delivery-enforcement routes a task to `uap deliver`, the tool runs a loop: the model produces code → real gates (build, typecheck, tests) validate → if anything fails, the error is fed back to the model → repeat until all gates pass.
|
|
66
|
+
|
|
67
|
+
**When it kicks in:** Automatically when delivery-enforcement blocks a direct source edit and the model needs to make actual code changes.
|
|
68
|
+
|
|
69
|
+
**Why it matters:** This is the single biggest uplift for small local models. A Qwen3.6-35B-A3B running locally with ~18GB VRAM will produce broken code on first try — but after 2-3 convergence iterations through real compiler feedback, it produces working code that matches what opus-4.8 would produce. The model learns from its mistakes in real-time.
|
|
70
|
+
|
|
71
|
+
### Model Presets
|
|
72
|
+
**What it does:** Pre-configured model profiles in `src/models/types.ts` that set optimal parameters (temperature, max tokens, reasoning effort) per model.
|
|
73
|
+
|
|
74
|
+
**When it kicks in:** Automatically when you select a model. The `qwen35-a3b` preset is the default for local models.
|
|
75
|
+
|
|
76
|
+
**Why it matters:** No manual tuning. The right parameters are applied automatically for each model family.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Memory & Context
|
|
81
|
+
|
|
82
|
+
### Semantic Memory Recall
|
|
83
|
+
**What it does:** 4-tier memory system (short-term, long-term, episodic, semantic) with vector-based semantic search. Relevant memories are auto-recalled based on prompt context.
|
|
84
|
+
|
|
85
|
+
**When it kicks in:** Every prompt — the system searches memory for relevant past sessions, decisions, and patterns.
|
|
86
|
+
|
|
87
|
+
**Why it matters:** The agent remembers your project conventions, past decisions, and architectural choices across sessions. No re-explaining context.
|
|
88
|
+
|
|
89
|
+
### MCP Router
|
|
90
|
+
**What it does:** Routes model tool calls through a centralized MCP (Model Context Protocol) router, reducing token usage by ~98% by batching and caching tool responses.
|
|
91
|
+
|
|
92
|
+
**When it kicks in:** Automatically for every tool call the model makes.
|
|
93
|
+
|
|
94
|
+
**Why it matters:** Massive token savings on repeated tool calls (file reads, git operations, etc.). Also enables consistent tool behavior across different models.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Coordination & Multi-Agent
|
|
99
|
+
|
|
100
|
+
### Coordination Layer
|
|
101
|
+
**What it does:** Orchestrates multi-agent workflows with deterministic control flow — fan-out, pipeline, barrier, and synthesis phases.
|
|
102
|
+
|
|
103
|
+
**When it kicks in:** When tasks are complex enough to warrant parallel subagents (e.g., "audit these 50 files" or "review changes across dimensions").
|
|
104
|
+
|
|
105
|
+
**Why it matters:** Parallel execution of independent tasks. A 10-file audit that would take 10 minutes sequentially completes in ~1 minute with 10 parallel agents.
|
|
106
|
+
|
|
107
|
+
### Deploy Batching
|
|
108
|
+
**What it does:** Batches multiple changes into a single deploy operation, reducing deploy overhead and ensuring atomicity.
|
|
109
|
+
|
|
110
|
+
**When it kicks in:** When multiple independent changes are ready for deployment.
|
|
111
|
+
|
|
112
|
+
**Why it matters:** Fewer deploys, faster delivery, atomic rollouts.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Developer Experience
|
|
117
|
+
|
|
118
|
+
### RTK (Rust Token Killer)
|
|
119
|
+
**What it does:** CLI proxy that intercepts common commands (`git status`, `npm install`, etc.) and rewrites them for token efficiency — 60-90% token savings on dev operations.
|
|
120
|
+
|
|
121
|
+
**When it kicks in:** Automatically for every shell command you run. No flags needed.
|
|
122
|
+
|
|
123
|
+
**Why it matters:** Token costs add up fast. RTK transparently optimizes every command without you thinking about it.
|
|
124
|
+
|
|
125
|
+
### HALO (High-Level Agent Orchestrator)
|
|
126
|
+
**What it does:** Provides a high-level orchestration layer for complex multi-step tasks, automatically decomposing them into subtasks and managing dependencies.
|
|
127
|
+
|
|
128
|
+
**When it kicks in:** When prompts are complex enough to warrant decomposition (substantial coding prompts, architectural changes, multi-file refactors).
|
|
129
|
+
|
|
130
|
+
**Why it matters:** You describe the goal, not the steps. HALO figures out the plan and executes it.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Local Model Setup
|
|
135
|
+
|
|
136
|
+
### llama.cpp + Qwen3.6-35B-A3B
|
|
137
|
+
**What it does:** Continuity server script (`scripts/run-llama-server-continuity.sh`) launches llama.cpp with optimal settings for the Qwen3.6-35B-A3B MoE model.
|
|
138
|
+
|
|
139
|
+
**When it kicks in:** When you need a local model for `uap deliver` convergence or as a coding agent backend.
|
|
140
|
+
|
|
141
|
+
**Why it matters:** See [Local Models](./LOCAL_MODELS.md) for VRAM-tiered setup instructions (8GB through 32GB). Key insight: `uap deliver` uplifts small models to punch well above their weight — a 35B-A3B running locally with real compiler feedback produces code quality comparable to much larger models.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Summary Table
|
|
146
|
+
|
|
147
|
+
| Feature | Auto? | Triggers On | Benefit |
|
|
148
|
+
|---------|-------|-------------|---------|
|
|
149
|
+
| Reactor (experts/skills/patterns) | ✅ | Every prompt | Domain expertise injected per-request |
|
|
150
|
+
| Delivery enforcement | ✅ | Source edits | Small models self-correct through real gates |
|
|
151
|
+
| `uap deliver` convergence | ✅ | When delivery routes | Broken code fixed before landing |
|
|
152
|
+
| Schema-diff gate | ✅ | Contract changes | No silent API breakage |
|
|
153
|
+
| Completion gates | ✅ | Task completion | Verified before "done" |
|
|
154
|
+
| Worktree enforcement | ✅ | Source edits | Clean git history |
|
|
155
|
+
| Semantic memory | ✅ | Every prompt | Context remembered across sessions |
|
|
156
|
+
| MCP router | ✅ | Every tool call | ~98% token reduction |
|
|
157
|
+
| Pattern RAG | ✅ | Every prompt | Battle-tested implementations |
|
|
158
|
+
| Coordination | ✅ | Complex tasks | Parallel subagent execution |
|
|
159
|
+
| Deploy batching | ✅ | Multiple changes | Atomic, efficient deploys |
|
|
160
|
+
| RTK | ✅ | Every command | 60-90% token savings |
|
|
161
|
+
| HALO | ✅ | Substantial prompts | Automatic task decomposition |
|
|
162
|
+
| Model presets | ✅ | Model selection | Optimal params per model |
|
|
163
|
+
|
|
164
|
+
**Bottom line:** Install UAP, point it at your model (Claude Opus, Qwen3.6, Llama — any), and everything just works. No configuration required.
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -150,6 +150,15 @@ PROXY_LOOP_REPEAT_THRESHOLD = int(os.environ.get("PROXY_LOOP_REPEAT_THRESHOLD",
|
|
|
150
150
|
PROXY_CYCLE_TRIGGER_REPEAT = int(os.environ.get("PROXY_CYCLE_TRIGGER_REPEAT", "3"))
|
|
151
151
|
PROXY_FORCED_THRESHOLD = int(os.environ.get("PROXY_FORCED_THRESHOLD", "15"))
|
|
152
152
|
PROXY_NO_PROGRESS_THRESHOLD = int(os.environ.get("PROXY_NO_PROGRESS_THRESHOLD", "3"))
|
|
153
|
+
# Fix D: streak-independent escape hatch. `no_progress_streak` resets to 0 on
|
|
154
|
+
# every turn whose last user message carries a tool_result (line ~3835) — i.e.
|
|
155
|
+
# every turn of a normal agentic loop — so the no_progress-gated LOOP BREAKER
|
|
156
|
+
# patterns can never accumulate. After this many *consecutive* forced-'required'
|
|
157
|
+
# turns (which DOES accumulate across an agentic loop via consecutive_forced_count),
|
|
158
|
+
# release tool_choice to 'auto' regardless of no_progress_streak so the model can
|
|
159
|
+
# emit a terminating response. Set well above any healthy run length (healthy
|
|
160
|
+
# loops hit auto/finalize/review phases that reset the count). 0 disables.
|
|
161
|
+
PROXY_FORCED_HARD_RELEASE = int(os.environ.get("PROXY_FORCED_HARD_RELEASE", "30"))
|
|
153
162
|
PROXY_CONTEXT_RELEASE_THRESHOLD = float(
|
|
154
163
|
os.environ.get("PROXY_CONTEXT_RELEASE_THRESHOLD", "0.90")
|
|
155
164
|
)
|
|
@@ -258,6 +267,34 @@ PROXY_FINALIZE_SESSION_HARD_CAP = int(
|
|
|
258
267
|
PROXY_RECON_CONVERGENCE_THRESHOLD = int(
|
|
259
268
|
os.environ.get("PROXY_RECON_CONVERGENCE_THRESHOLD", "40")
|
|
260
269
|
)
|
|
270
|
+
# Fix E: the recon hard tier (streak >= 2x threshold) fires a directive + flips
|
|
271
|
+
# tool_choice to 'auto', but `consecutive_no_write_turns` resets to 0 whenever
|
|
272
|
+
# the model emits any write tool — so a loop that periodically writes sawtooths
|
|
273
|
+
# the streak (observed: 90 -> 0 -> climb again), re-triggering the hard tier
|
|
274
|
+
# forever and never actually terminating. This counts how many times the hard
|
|
275
|
+
# tier has fired across the whole session (monotonic, never reset). Once it
|
|
276
|
+
# reaches this cap, the guard escalates: it strips tools for the turn so the
|
|
277
|
+
# model is forced to emit a terminal prose summary, breaking the sawtooth. 0
|
|
278
|
+
# disables the escalation (hard tier still flips to 'auto' each time).
|
|
279
|
+
PROXY_RECON_SESSION_HARD_CAP = int(
|
|
280
|
+
os.environ.get("PROXY_RECON_SESSION_HARD_CAP", "3")
|
|
281
|
+
)
|
|
282
|
+
# Fix F: context death-spiral breaker. When the *raw* (pre-prune) incoming
|
|
283
|
+
# context stays catastrophically over the window for several consecutive turns,
|
|
284
|
+
# releasing tool_choice to 'auto' (Fix B / LOOP BREAKER) is NOT enough — the
|
|
285
|
+
# model keeps voluntarily emitting tool calls and the client keeps resending an
|
|
286
|
+
# ever-growing transcript (observed: ctx 936%, model emits tool_calls 18/min
|
|
287
|
+
# despite tool_choice=auto). After this many consecutive turns at/above the
|
|
288
|
+
# ratio, strip tools entirely so the only possible response is a terminal text
|
|
289
|
+
# summary (end_turn), which ends the client's agentic loop. Ratio is set high
|
|
290
|
+
# enough that only a true runaway trips it — a merely-full session tops out near
|
|
291
|
+
# 100-130%, never 300%. 0 disables.
|
|
292
|
+
PROXY_RAW_CTX_FINALIZE_RATIO = float(
|
|
293
|
+
os.environ.get("PROXY_RAW_CTX_FINALIZE_RATIO", "3.0")
|
|
294
|
+
)
|
|
295
|
+
PROXY_RAW_CTX_FINALIZE_STREAK = int(
|
|
296
|
+
os.environ.get("PROXY_RAW_CTX_FINALIZE_STREAK", "2")
|
|
297
|
+
)
|
|
261
298
|
PROXY_STREAM_REASONING_FALLBACK = (
|
|
262
299
|
os.environ.get("PROXY_STREAM_REASONING_FALLBACK", "off").strip().lower()
|
|
263
300
|
)
|
|
@@ -800,6 +837,13 @@ class SessionMonitor:
|
|
|
800
837
|
last_input_tokens: int = 0 # Estimated input tokens of last request
|
|
801
838
|
last_output_tokens: int = 0 # Actual output tokens of last response
|
|
802
839
|
peak_input_tokens: int = 0 # High-water mark
|
|
840
|
+
# Fix B: the incoming (pre-prune) token count for the current request. The
|
|
841
|
+
# proxy prunes the conversation and then calls record_request() again with
|
|
842
|
+
# the post-prune total, so last_input_tokens / get_utilization() reflect the
|
|
843
|
+
# *pruned* size (~30%) by the time the tool_choice guards run — masking the
|
|
844
|
+
# fact that the client just sent e.g. 800% of the window. This preserves the
|
|
845
|
+
# raw size so LOOP BREAKER pattern 3 can release on real context blow-up.
|
|
846
|
+
pre_prune_input_tokens: int = 0
|
|
803
847
|
prune_count: int = 0 # How many times pruning was triggered
|
|
804
848
|
overflow_count: int = 0 # How many context overflow errors caught
|
|
805
849
|
prune_drop_count: int = 0 # monotonic: # of oldest middle msgs pruned (B3)
|
|
@@ -818,6 +862,8 @@ class SessionMonitor:
|
|
|
818
862
|
loop_warnings_emitted: int = 0 # How many loop warnings sent to the model
|
|
819
863
|
no_progress_streak: int = 0 # Forced tool turns without new tool_result
|
|
820
864
|
consecutive_no_write_turns: int = 0 # turns exploring with no write tool (B1)
|
|
865
|
+
recon_hard_fires: int = 0 # Fix E: monotonic count of recon hard-tier firings
|
|
866
|
+
catastrophic_ctx_streak: int = 0 # Fix F: consecutive turns raw ctx >= finalize ratio
|
|
821
867
|
unexpected_end_turn_count: int = 0 # end_turn without tool_use in active loop
|
|
822
868
|
tool_starvation_streak: int = 0 # Consecutive forced turns with no tool_calls produced
|
|
823
869
|
malformed_tool_streak: int = 0 # consecutive malformed pseudo tool payloads
|
|
@@ -878,6 +924,18 @@ class SessionMonitor:
|
|
|
878
924
|
return 0.0
|
|
879
925
|
return self.last_input_tokens / self.context_window
|
|
880
926
|
|
|
927
|
+
def get_raw_utilization(self) -> float:
|
|
928
|
+
"""Pre-prune context utilization for the current request (Fix B).
|
|
929
|
+
|
|
930
|
+
Reflects what the client actually sent this turn, before the proxy
|
|
931
|
+
pruned it. Used by the loop breaker so a runaway client that resends
|
|
932
|
+
800% of the window each turn is detected even though post-prune
|
|
933
|
+
utilization reads ~30%. Returns 0.0 until the first request is recorded.
|
|
934
|
+
"""
|
|
935
|
+
if self.context_window <= 0:
|
|
936
|
+
return 0.0
|
|
937
|
+
return self.pre_prune_input_tokens / self.context_window
|
|
938
|
+
|
|
881
939
|
def get_warning_level(self) -> str | None:
|
|
882
940
|
"""Return warning level based on context utilization.
|
|
883
941
|
Returns None if no warning needed."""
|
|
@@ -1238,12 +1296,37 @@ class SessionMonitor:
|
|
|
1238
1296
|
self.loop_warnings_emitted += 1
|
|
1239
1297
|
return True
|
|
1240
1298
|
|
|
1241
|
-
# Pattern
|
|
1242
|
-
|
|
1299
|
+
# Pattern 2b (Fix D): streak-independent forced-count ceiling. In an
|
|
1300
|
+
# agentic loop no_progress_streak resets every turn (tool_result always
|
|
1301
|
+
# present), so Pattern 2 never fires. consecutive_forced_count, however,
|
|
1302
|
+
# accumulates across the loop. Release once it crosses the hard ceiling
|
|
1303
|
+
# regardless of no_progress_streak so the model can terminate.
|
|
1304
|
+
if (
|
|
1305
|
+
PROXY_FORCED_HARD_RELEASE > 0
|
|
1306
|
+
and self.consecutive_forced_count >= PROXY_FORCED_HARD_RELEASE
|
|
1307
|
+
):
|
|
1308
|
+
logger.warning(
|
|
1309
|
+
"LOOP BREAKER: %d consecutive forced tool_choice requests (hard ceiling %d) -- "
|
|
1310
|
+
"releasing to 'auto' regardless of progress streak.",
|
|
1311
|
+
self.consecutive_forced_count,
|
|
1312
|
+
PROXY_FORCED_HARD_RELEASE,
|
|
1313
|
+
)
|
|
1314
|
+
self.loop_warnings_emitted += 1
|
|
1315
|
+
return True
|
|
1316
|
+
|
|
1317
|
+
# Pattern 3: Context almost full -- let model wrap up naturally.
|
|
1318
|
+
# Fix B: check BOTH post-prune utilization and the raw pre-prune size.
|
|
1319
|
+
# The proxy prunes before this runs, so get_utilization() reads ~30%
|
|
1320
|
+
# even when the client just sent 800% of the window; get_raw_utilization()
|
|
1321
|
+
# exposes the real blow-up so a runaway client is actually released.
|
|
1322
|
+
eff_util = max(self.get_utilization(), self.get_raw_utilization())
|
|
1323
|
+
if eff_util >= PROXY_CONTEXT_RELEASE_THRESHOLD:
|
|
1243
1324
|
logger.warning(
|
|
1244
|
-
"LOOP BREAKER: Context utilization %.1f%% --
|
|
1245
|
-
"tool_choice to let model wrap up.",
|
|
1325
|
+
"LOOP BREAKER: Context utilization %.1f%% (post-prune %.1f%%, raw %.1f%%) -- "
|
|
1326
|
+
"releasing tool_choice to let model wrap up.",
|
|
1327
|
+
eff_util * 100,
|
|
1246
1328
|
self.get_utilization() * 100,
|
|
1329
|
+
self.get_raw_utilization() * 100,
|
|
1247
1330
|
)
|
|
1248
1331
|
return True
|
|
1249
1332
|
|
|
@@ -3397,8 +3480,32 @@ def _maybe_inject_recon_convergence(
|
|
|
3397
3480
|
streak = monitor.consecutive_no_write_turns
|
|
3398
3481
|
if streak < PROXY_RECON_CONVERGENCE_THRESHOLD:
|
|
3399
3482
|
return
|
|
3400
|
-
|
|
3401
|
-
|
|
3483
|
+
# Report the *raw* (pre-prune) utilization — post-prune util understates the
|
|
3484
|
+
# blow-up (~30%) and makes the directive's "context is at X%" misleading.
|
|
3485
|
+
util = max(monitor.get_utilization(), monitor.get_raw_utilization())
|
|
3486
|
+
hard = streak >= 2 * PROXY_RECON_CONVERGENCE_THRESHOLD
|
|
3487
|
+
escalate = False
|
|
3488
|
+
if hard:
|
|
3489
|
+
monitor.recon_hard_fires += 1 # Fix E: monotonic, never reset
|
|
3490
|
+
escalate = (
|
|
3491
|
+
PROXY_RECON_SESSION_HARD_CAP > 0
|
|
3492
|
+
and monitor.recon_hard_fires >= PROXY_RECON_SESSION_HARD_CAP
|
|
3493
|
+
)
|
|
3494
|
+
|
|
3495
|
+
if escalate:
|
|
3496
|
+
# Fix E: the hard tier has fired repeatedly this session — the model
|
|
3497
|
+
# keeps writing just enough to reset consecutive_no_write_turns, then
|
|
3498
|
+
# re-diverges, sawtoothing the streak and re-triggering the hard tier
|
|
3499
|
+
# forever. Stop negotiating: strip tools so the model MUST emit a
|
|
3500
|
+
# terminal plain-text summary, breaking the sawtooth for good.
|
|
3501
|
+
directive = (
|
|
3502
|
+
f"STOP. You have hit the exploration limit {monitor.recon_hard_fires} "
|
|
3503
|
+
f"times in this session and context is at {util * 100:.0f}%. No tools "
|
|
3504
|
+
"are available this turn. Reply NOW with a plain-text summary of what "
|
|
3505
|
+
"you found and what remains — this ends the task."
|
|
3506
|
+
)
|
|
3507
|
+
tier = "hard-escalated"
|
|
3508
|
+
elif hard:
|
|
3402
3509
|
directive = (
|
|
3403
3510
|
f"STOP exploring. You have run {streak} consecutive turns of "
|
|
3404
3511
|
f"exploration without producing a deliverable and context is at "
|
|
@@ -3421,27 +3528,43 @@ def _maybe_inject_recon_convergence(
|
|
|
3421
3528
|
msgs.append({"role": "user", "content": directive})
|
|
3422
3529
|
openai_body["messages"] = msgs
|
|
3423
3530
|
|
|
3424
|
-
# Re-inject any write/deliverable tool that narrowing dropped, so the
|
|
3425
|
-
# "write your deliverable" directive is actually satisfiable. Without
|
|
3426
|
-
# this the model is told to write but has no write tool to call, picks
|
|
3427
|
-
# another read tool, and the streak climbs unbounded.
|
|
3428
3531
|
restored: list[str] = []
|
|
3429
|
-
if
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3532
|
+
if escalate:
|
|
3533
|
+
# Strip tools entirely so the only possible response is terminal prose.
|
|
3534
|
+
openai_body.pop("tools", None)
|
|
3535
|
+
openai_body.pop("tool_choice", None)
|
|
3536
|
+
openai_body.pop("grammar", None)
|
|
3537
|
+
else:
|
|
3538
|
+
if hard:
|
|
3539
|
+
# Fix C: at the hard tier, drop the structural requirement to call a
|
|
3540
|
+
# tool. Earlier logic forced tool_choice='required' for the active
|
|
3541
|
+
# agentic loop, which directly contradicts "produce your deliverable
|
|
3542
|
+
# NOW / do not run anything else" — the model is forbidden from
|
|
3543
|
+
# terminating and must emit yet another tool call, so the streak
|
|
3544
|
+
# climbs unbounded. Releasing to 'auto' lets it actually write/stop.
|
|
3545
|
+
openai_body["tool_choice"] = "auto"
|
|
3546
|
+
openai_body.pop("grammar", None)
|
|
3547
|
+
# Re-inject any write/deliverable tool that narrowing dropped, so the
|
|
3548
|
+
# "write your deliverable" directive is actually satisfiable. Without
|
|
3549
|
+
# this the model is told to write but has no write tool to call, picks
|
|
3550
|
+
# another read tool, and the streak climbs unbounded.
|
|
3551
|
+
if full_tools:
|
|
3552
|
+
present = {
|
|
3553
|
+
(t.get("function", {}).get("name", "") or "").lower()
|
|
3554
|
+
for t in openai_body.get("tools", [])
|
|
3555
|
+
}
|
|
3556
|
+
for tool in full_tools:
|
|
3557
|
+
name = (tool.get("function", {}).get("name", "") or "")
|
|
3558
|
+
if name.lower() in _WRITE_TOOL_CLASS and name.lower() not in present:
|
|
3559
|
+
openai_body.setdefault("tools", []).append(tool)
|
|
3560
|
+
present.add(name.lower())
|
|
3561
|
+
restored.append(name)
|
|
3440
3562
|
|
|
3441
3563
|
logger.warning(
|
|
3442
|
-
"RECON CONVERGENCE: injected %s directive (no_write_streak=%d,
|
|
3443
|
-
"restored_write_tools=%s)",
|
|
3444
|
-
tier, streak, util * 100,
|
|
3564
|
+
"RECON CONVERGENCE: injected %s directive (no_write_streak=%d, hard_fires=%d, "
|
|
3565
|
+
"ctx=%.0f%%, tool_choice=%s, restored_write_tools=%s)",
|
|
3566
|
+
tier, streak, monitor.recon_hard_fires, util * 100,
|
|
3567
|
+
openai_body.get("tool_choice", "stripped"), restored or "none",
|
|
3445
3568
|
)
|
|
3446
3569
|
|
|
3447
3570
|
|
|
@@ -3751,6 +3874,46 @@ def build_openai_request(
|
|
|
3751
3874
|
last_user_has_tool_result,
|
|
3752
3875
|
)
|
|
3753
3876
|
|
|
3877
|
+
# CONTEXT DEATH-SPIRAL BREAKER (Fix F): raw incoming context has been
|
|
3878
|
+
# catastrophically over the window for several consecutive turns. The
|
|
3879
|
+
# LOOP BREAKER already released tool_choice to 'auto', but the model
|
|
3880
|
+
# keeps voluntarily emitting tool calls and the client keeps resending a
|
|
3881
|
+
# growing transcript, so the loop never ends. Strip tools entirely so
|
|
3882
|
+
# the only possible output is a terminal text summary (end_turn), which
|
|
3883
|
+
# ends the client's agentic loop. Gated high (raw ctx >= 300% for >= N
|
|
3884
|
+
# turns) so only a true runaway trips it, never a merely-full session.
|
|
3885
|
+
if (
|
|
3886
|
+
PROXY_RAW_CTX_FINALIZE_STREAK > 0
|
|
3887
|
+
and monitor.catastrophic_ctx_streak >= PROXY_RAW_CTX_FINALIZE_STREAK
|
|
3888
|
+
):
|
|
3889
|
+
openai_body.pop("tool_choice", None)
|
|
3890
|
+
openai_body.pop("tools", None)
|
|
3891
|
+
openai_body.pop("grammar", None)
|
|
3892
|
+
msgs = openai_body.get("messages", [])
|
|
3893
|
+
msgs.append({
|
|
3894
|
+
"role": "user",
|
|
3895
|
+
"content": (
|
|
3896
|
+
"The conversation has exceeded the context window "
|
|
3897
|
+
f"({monitor.get_raw_utilization() * 100:.0f}%) and cannot "
|
|
3898
|
+
"continue. No tools are available. Reply with a brief "
|
|
3899
|
+
"plain-text summary of what was accomplished and what "
|
|
3900
|
+
"remains, then stop."
|
|
3901
|
+
),
|
|
3902
|
+
})
|
|
3903
|
+
openai_body["messages"] = msgs
|
|
3904
|
+
monitor.reset_tool_turn_state(reason="context_death_spiral_breaker")
|
|
3905
|
+
logger.error(
|
|
3906
|
+
"CONTEXT DEATH-SPIRAL BREAKER: raw ctx %.0f%% for %d consecutive "
|
|
3907
|
+
"turns -- stripped tools to force terminal summary (end_turn).",
|
|
3908
|
+
monitor.get_raw_utilization() * 100,
|
|
3909
|
+
monitor.catastrophic_ctx_streak,
|
|
3910
|
+
)
|
|
3911
|
+
if PROXY_DISABLE_THINKING_ON_TOOL_TURNS:
|
|
3912
|
+
openai_body["enable_thinking"] = False
|
|
3913
|
+
if PROXY_DISABLE_SPEC_ON_TOOL_TURNS:
|
|
3914
|
+
openai_body["speculative.n_max"] = 0
|
|
3915
|
+
return openai_body
|
|
3916
|
+
|
|
3754
3917
|
# TOOL STARVATION BREAKER: if model repeatedly fails to produce tool
|
|
3755
3918
|
# calls despite required, strip tools to let it generate text and break
|
|
3756
3919
|
# the forcing loop.
|
|
@@ -7834,6 +7997,20 @@ async def messages(request: Request):
|
|
|
7834
7997
|
estimated_tokens,
|
|
7835
7998
|
)
|
|
7836
7999
|
utilization = effective_tokens / ctx_window
|
|
8000
|
+
# Fix B: preserve the raw incoming size before any pruning rewrites
|
|
8001
|
+
# last_input_tokens to the post-prune total, so the loop breaker can
|
|
8002
|
+
# see the true blow-up at build_openai_request time.
|
|
8003
|
+
monitor.pre_prune_input_tokens = effective_tokens
|
|
8004
|
+
# Fix F: track consecutive turns whose raw incoming context is
|
|
8005
|
+
# catastrophically over the window (a death spiral the per-request
|
|
8006
|
+
# pruner can mask but not cure). build_openai_request acts on this.
|
|
8007
|
+
if (
|
|
8008
|
+
PROXY_RAW_CTX_FINALIZE_RATIO > 0
|
|
8009
|
+
and utilization >= PROXY_RAW_CTX_FINALIZE_RATIO
|
|
8010
|
+
):
|
|
8011
|
+
monitor.catastrophic_ctx_streak += 1
|
|
8012
|
+
else:
|
|
8013
|
+
monitor.catastrophic_ctx_streak = 0
|
|
7837
8014
|
if utilization >= PROXY_CONTEXT_PRUNE_THRESHOLD:
|
|
7838
8015
|
logger.warning(
|
|
7839
8016
|
"Context utilization %.1f%% exceeds threshold %.1f%% -- pruning conversation",
|