@miller-tech/uap 1.136.1 → 1.137.1

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.
Files changed (133) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/benchmarks/paired/report.d.ts +13 -0
  3. package/dist/benchmarks/paired/report.d.ts.map +1 -1
  4. package/dist/benchmarks/paired/report.js +29 -3
  5. package/dist/benchmarks/paired/report.js.map +1 -1
  6. package/dist/benchmarks/paired/types.d.ts +59 -0
  7. package/dist/benchmarks/paired/types.d.ts.map +1 -1
  8. package/dist/benchmarks/paired/types.js +60 -0
  9. package/dist/benchmarks/paired/types.js.map +1 -1
  10. package/dist/bin/cli.js +30 -0
  11. package/dist/bin/cli.js.map +1 -1
  12. package/dist/cli/deliver.d.ts.map +1 -1
  13. package/dist/cli/deliver.js +111 -7
  14. package/dist/cli/deliver.js.map +1 -1
  15. package/dist/cli/react.d.ts.map +1 -1
  16. package/dist/cli/react.js +18 -0
  17. package/dist/cli/react.js.map +1 -1
  18. package/dist/cli/self-tuning.d.ts +33 -0
  19. package/dist/cli/self-tuning.d.ts.map +1 -0
  20. package/dist/cli/self-tuning.js +139 -0
  21. package/dist/cli/self-tuning.js.map +1 -0
  22. package/dist/cli/tune-adapter.d.ts +8 -0
  23. package/dist/cli/tune-adapter.d.ts.map +1 -0
  24. package/dist/cli/tune-adapter.js +26 -0
  25. package/dist/cli/tune-adapter.js.map +1 -0
  26. package/dist/config/settings-registry.d.ts.map +1 -1
  27. package/dist/config/settings-registry.js +10 -0
  28. package/dist/config/settings-registry.js.map +1 -1
  29. package/dist/coordination/adaptation-signal.d.ts +19 -0
  30. package/dist/coordination/adaptation-signal.d.ts.map +1 -0
  31. package/dist/coordination/adaptation-signal.js +36 -0
  32. package/dist/coordination/adaptation-signal.js.map +1 -0
  33. package/dist/delivery/agentic-executor.d.ts +16 -1
  34. package/dist/delivery/agentic-executor.d.ts.map +1 -1
  35. package/dist/delivery/agentic-executor.js +45 -4
  36. package/dist/delivery/agentic-executor.js.map +1 -1
  37. package/dist/delivery/decompose.d.ts +27 -0
  38. package/dist/delivery/decompose.d.ts.map +1 -1
  39. package/dist/delivery/decompose.js +31 -1
  40. package/dist/delivery/decompose.js.map +1 -1
  41. package/dist/delivery/repair-escalation.d.ts +49 -0
  42. package/dist/delivery/repair-escalation.d.ts.map +1 -0
  43. package/dist/delivery/repair-escalation.js +83 -0
  44. package/dist/delivery/repair-escalation.js.map +1 -0
  45. package/dist/delivery/verifier-ladder.d.ts +47 -0
  46. package/dist/delivery/verifier-ladder.d.ts.map +1 -1
  47. package/dist/delivery/verifier-ladder.js +87 -1
  48. package/dist/delivery/verifier-ladder.js.map +1 -1
  49. package/dist/self-harness/mods.d.ts +20 -1
  50. package/dist/self-harness/mods.d.ts.map +1 -1
  51. package/dist/self-harness/mods.js +41 -0
  52. package/dist/self-harness/mods.js.map +1 -1
  53. package/dist/self-harness/orchestrator.js +4 -0
  54. package/dist/self-harness/orchestrator.js.map +1 -1
  55. package/dist/self-harness/transfer.d.ts.map +1 -1
  56. package/dist/self-harness/transfer.js +2 -0
  57. package/dist/self-harness/transfer.js.map +1 -1
  58. package/dist/self-tuning/flag-writer.d.ts +48 -0
  59. package/dist/self-tuning/flag-writer.d.ts.map +1 -0
  60. package/dist/self-tuning/flag-writer.js +102 -0
  61. package/dist/self-tuning/flag-writer.js.map +1 -0
  62. package/dist/self-tuning/flags.d.ts +88 -0
  63. package/dist/self-tuning/flags.d.ts.map +1 -0
  64. package/dist/self-tuning/flags.js +189 -0
  65. package/dist/self-tuning/flags.js.map +1 -0
  66. package/dist/self-tuning/index.d.ts +25 -0
  67. package/dist/self-tuning/index.d.ts.map +1 -0
  68. package/dist/self-tuning/index.js +25 -0
  69. package/dist/self-tuning/index.js.map +1 -0
  70. package/dist/self-tuning/judge.d.ts +66 -0
  71. package/dist/self-tuning/judge.d.ts.map +1 -0
  72. package/dist/self-tuning/judge.js +145 -0
  73. package/dist/self-tuning/judge.js.map +1 -0
  74. package/dist/self-tuning/llm-tuner.d.ts +83 -0
  75. package/dist/self-tuning/llm-tuner.d.ts.map +1 -0
  76. package/dist/self-tuning/llm-tuner.js +191 -0
  77. package/dist/self-tuning/llm-tuner.js.map +1 -0
  78. package/dist/self-tuning/orchestrator.d.ts +90 -0
  79. package/dist/self-tuning/orchestrator.d.ts.map +1 -0
  80. package/dist/self-tuning/orchestrator.js +126 -0
  81. package/dist/self-tuning/orchestrator.js.map +1 -0
  82. package/dist/self-tuning/paired-validator.d.ts +50 -0
  83. package/dist/self-tuning/paired-validator.d.ts.map +1 -0
  84. package/dist/self-tuning/paired-validator.js +78 -0
  85. package/dist/self-tuning/paired-validator.js.map +1 -0
  86. package/dist/self-tuning/profiles/index.d.ts +11 -0
  87. package/dist/self-tuning/profiles/index.d.ts.map +1 -0
  88. package/dist/self-tuning/profiles/index.js +15 -0
  89. package/dist/self-tuning/profiles/index.js.map +1 -0
  90. package/dist/self-tuning/profiles/opus48.d.ts +11 -0
  91. package/dist/self-tuning/profiles/opus48.d.ts.map +1 -0
  92. package/dist/self-tuning/profiles/opus48.js +27 -0
  93. package/dist/self-tuning/profiles/opus48.js.map +1 -0
  94. package/dist/self-tuning/profiles/qwen36.d.ts +11 -0
  95. package/dist/self-tuning/profiles/qwen36.d.ts.map +1 -0
  96. package/dist/self-tuning/profiles/qwen36.js +33 -0
  97. package/dist/self-tuning/profiles/qwen36.js.map +1 -0
  98. package/dist/self-tuning/quality-scorer.d.ts +90 -0
  99. package/dist/self-tuning/quality-scorer.d.ts.map +1 -0
  100. package/dist/self-tuning/quality-scorer.js +180 -0
  101. package/dist/self-tuning/quality-scorer.js.map +1 -0
  102. package/dist/self-tuning/realtime-adaptor.d.ts +78 -0
  103. package/dist/self-tuning/realtime-adaptor.d.ts.map +1 -0
  104. package/dist/self-tuning/realtime-adaptor.js +127 -0
  105. package/dist/self-tuning/realtime-adaptor.js.map +1 -0
  106. package/dist/self-tuning/run.d.ts +61 -0
  107. package/dist/self-tuning/run.d.ts.map +1 -0
  108. package/dist/self-tuning/run.js +122 -0
  109. package/dist/self-tuning/run.js.map +1 -0
  110. package/dist/self-tuning/search-reducer.d.ts +76 -0
  111. package/dist/self-tuning/search-reducer.d.ts.map +1 -0
  112. package/dist/self-tuning/search-reducer.js +349 -0
  113. package/dist/self-tuning/search-reducer.js.map +1 -0
  114. package/dist/self-tuning/tuning-profile.d.ts +72 -0
  115. package/dist/self-tuning/tuning-profile.d.ts.map +1 -0
  116. package/dist/self-tuning/tuning-profile.js +134 -0
  117. package/dist/self-tuning/tuning-profile.js.map +1 -0
  118. package/dist/telemetry/session-telemetry.d.ts +25 -0
  119. package/dist/telemetry/session-telemetry.d.ts.map +1 -1
  120. package/dist/telemetry/session-telemetry.js +32 -0
  121. package/dist/telemetry/session-telemetry.js.map +1 -1
  122. package/dist/types/config.d.ts +13 -0
  123. package/dist/types/config.d.ts.map +1 -1
  124. package/dist/types/config.js +3 -0
  125. package/dist/types/config.js.map +1 -1
  126. package/docs/design/LLM_SELF_TUNING_ANALYSIS.md +617 -0
  127. package/docs/guides/SELF_TUNING.md +137 -0
  128. package/package.json +1 -1
  129. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  130. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  131. package/tools/agents/scripts/anthropic_proxy.py +355 -29
  132. package/tools/agents/scripts/confidence_escalation.py +60 -4
  133. package/tools/agents/tests/test_confidence_escalation.py +77 -0
@@ -0,0 +1,180 @@
1
+ /**
2
+ * LLM Self-Tuning — the Quality Scorer (P0).
3
+ *
4
+ * The paired benchmark answers "did the code work" (pass/fail). Raising a small
5
+ * model toward Opus 4.8 is a QUALITY problem, not just a correctness one, so the
6
+ * tuner needs a richer signal. This module produces a `QualityScore`
7
+ * (correctness, quality, efficiency, toolReliability, planning + composite) per
8
+ * run so the tuner has something continuous to optimize.
9
+ *
10
+ * Two production paths, chosen by whether a judge model is available:
11
+ * - HEURISTIC (no judge): every dimension derived deterministically from the
12
+ * metric vector + ground-truth `correct`. Zero cost, fully reproducible,
13
+ * network-free — the default and the test path.
14
+ * - JUDGE (a stronger model configured): correctness/quality/planning graded
15
+ * by the judge over the task spec + agent output; efficiency/toolReliability
16
+ * stay deterministic (they are metric facts, not opinions). The two are
17
+ * fused into a 'hybrid' score.
18
+ *
19
+ * The composite weighting (correctness 40 / quality 30 / efficiency 15 /
20
+ * toolReliability 15) matches docs/design/LLM_SELF_TUNING_ANALYSIS.md §3.3.1.
21
+ */
22
+ import { QualityScoreSchema, compositeQuality, DEFAULT_QUALITY_WEIGHTS, } from '../benchmarks/paired/types.js';
23
+ import { parseJsonLenient } from './judge.js';
24
+ const DEFAULT_REF_TOKENS = 15000;
25
+ const DEFAULT_REF_TURNS = 6;
26
+ function clamp100(n) {
27
+ return Math.max(0, Math.min(100, n));
28
+ }
29
+ /**
30
+ * Deterministic efficiency (0-100). An INCORRECT run spent its tokens on a wrong
31
+ * answer, so efficiency is heavily penalized (tokens were wasted). A correct run
32
+ * scores by leanness against `refTokens`.
33
+ */
34
+ export function efficiencyScore(metrics, refTokens = DEFAULT_REF_TOKENS) {
35
+ const tokens = metrics.tokens;
36
+ if (tokens == null)
37
+ return metrics.correct ? 60 : 20; // unknown spend: neutral-ish
38
+ const leanness = (refTokens / (refTokens + Math.max(0, tokens))) * 100; // 100→50→0
39
+ return clamp100(metrics.correct ? leanness : leanness * 0.3);
40
+ }
41
+ /**
42
+ * Deterministic tool reliability (0-100) from well-formedness + productivity.
43
+ * A malformed edit is the small-model failure mode this dimension surfaces.
44
+ */
45
+ export function toolReliabilityScore(metrics) {
46
+ let base;
47
+ if (metrics.wellFormed === false)
48
+ base = 30;
49
+ else if (metrics.wellFormed === true)
50
+ base = 90;
51
+ else
52
+ base = 70; // unknown
53
+ // Productivity: a run that made tool calls but never got correct is churning.
54
+ const productivity = metrics.correct ? 1 : 0.7;
55
+ // Penalize a run that made no tool calls yet was expected to act.
56
+ if (metrics.toolCalls != null && metrics.toolCalls === 0 && !metrics.correct)
57
+ base *= 0.7;
58
+ return clamp100(base * productivity);
59
+ }
60
+ /** Deterministic planning heuristic (0-100): correct + few turns == coherent. */
61
+ export function planningScore(metrics, refTurns = DEFAULT_REF_TURNS) {
62
+ const turns = metrics.turns;
63
+ const floor = metrics.correct ? 60 : 25;
64
+ if (turns == null)
65
+ return floor;
66
+ // Fewer turns than the reference reads as tighter planning; more reads looser.
67
+ const turnFactor = refTurns / (refTurns + Math.max(0, turns - refTurns));
68
+ return clamp100(floor + (metrics.correct ? 40 : 15) * turnFactor);
69
+ }
70
+ /**
71
+ * Purely deterministic score — no network. Correctness is the ground-truth
72
+ * boolean projected to 0/100; quality is proxied from correctness + wellFormed;
73
+ * the rest come from the heuristics above. This is the default and test path.
74
+ */
75
+ export function heuristicQuality(input, opts = {}) {
76
+ const m = input.metrics;
77
+ const correctness = input.correct ? 100 : 0;
78
+ // Quality proxy: a correct, well-formed answer is decent; without a judge we
79
+ // cannot see nuance, so we stay conservative (never award judge-level highs).
80
+ const qualityProxy = input.correct ? (m.wellFormed === false ? 60 : 78) : m.wellFormed === true ? 30 : 20;
81
+ const dims = {
82
+ correctness,
83
+ quality: qualityProxy,
84
+ efficiency: efficiencyScore(m, opts.refTokens),
85
+ toolReliability: toolReliabilityScore(m),
86
+ planning: planningScore(m, opts.refTurns),
87
+ };
88
+ const composite = compositeQuality(dims, opts.weights ?? DEFAULT_QUALITY_WEIGHTS);
89
+ return QualityScoreSchema.parse({ ...dims, composite, source: 'heuristic' });
90
+ }
91
+ /** Build the judge prompt: grade correctness/quality/planning as 0-100 JSON. */
92
+ export function buildJudgePrompt(input, maxOutputChars) {
93
+ const output = (input.output ?? '').slice(0, maxOutputChars);
94
+ return [
95
+ 'You are a strict senior engineer grading an AI agent\'s work on a task.',
96
+ 'Grade three dimensions on a 0-100 scale, where 100 is what a top-tier model',
97
+ '(Claude Opus) would produce and 50 is mediocre-but-acceptable.',
98
+ '',
99
+ 'DIMENSIONS:',
100
+ '- correctness: does the work actually satisfy the task as specified?',
101
+ '- quality: is the solution clean, idiomatic, complete, and free of shortcuts?',
102
+ '- planning: is the approach coherent and well-sequenced (vs flailing)?',
103
+ '',
104
+ `GROUND TRUTH (from a hidden deterministic test): the task was ${input.correct ? 'RESOLVED' : 'NOT resolved'}.`,
105
+ 'Weight correctness heavily toward that ground truth, but you may still judge',
106
+ 'quality/planning on partial or over-engineered work.',
107
+ '',
108
+ 'TASK INSTRUCTION:',
109
+ input.taskInstruction,
110
+ ...(input.reference ? ['', 'REFERENCE / RUBRIC:', input.reference] : []),
111
+ '',
112
+ 'AGENT OUTPUT (diff / answer / log tail):',
113
+ output || '(no output captured)',
114
+ '',
115
+ 'Respond with ONLY a JSON object, no prose:',
116
+ '{"correctness": <0-100>, "quality": <0-100>, "planning": <0-100>, "rationale": "<one sentence>"}',
117
+ ].join('\n');
118
+ }
119
+ /**
120
+ * Score a single run. Uses the judge for correctness/quality/planning when one
121
+ * is supplied and reachable; efficiency/toolReliability are always the
122
+ * deterministic metric facts. Any judge failure degrades gracefully to the
123
+ * heuristic score (never throws), so a scoring pass can never wedge a bench.
124
+ */
125
+ export async function scoreQuality(input, opts = {}) {
126
+ const heuristic = heuristicQuality(input, opts);
127
+ if (!opts.judge)
128
+ return heuristic;
129
+ const maxOut = opts.maxOutputChars ?? 6000;
130
+ let verdict = null;
131
+ try {
132
+ const raw = await opts.judge.complete(buildJudgePrompt(input, maxOut), { json: true, temperature: 0.1 });
133
+ verdict = parseJsonLenient(raw);
134
+ }
135
+ catch {
136
+ verdict = null; // network/parse failure → heuristic fallback
137
+ }
138
+ if (!verdict || typeof verdict.correctness !== 'number')
139
+ return heuristic;
140
+ const num = (v, fallback) => typeof v === 'number' && Number.isFinite(v) ? clamp100(v) : fallback;
141
+ const dims = {
142
+ // Anchor judged correctness to ground truth: a judge that contradicts the
143
+ // hidden test is pulled toward it (70/30) so a hallucinated pass can't win.
144
+ correctness: clamp100(0.3 * num(verdict.correctness, input.correct ? 100 : 0) + 0.7 * (input.correct ? 100 : 0)),
145
+ quality: num(verdict.quality, heuristic.quality),
146
+ efficiency: heuristic.efficiency,
147
+ toolReliability: heuristic.toolReliability,
148
+ planning: num(verdict.planning, heuristic.planning),
149
+ };
150
+ const composite = compositeQuality(dims, opts.weights ?? DEFAULT_QUALITY_WEIGHTS);
151
+ return QualityScoreSchema.parse({
152
+ ...dims,
153
+ composite,
154
+ source: 'hybrid',
155
+ ...(verdict.rationale ? { rationale: String(verdict.rationale).slice(0, 300) } : {}),
156
+ });
157
+ }
158
+ /**
159
+ * Attach quality scores to a set of run records in place-returning form. The
160
+ * `inputFor` mapper supplies the per-record evidence (task instruction, output).
161
+ * Scoring is bounded-concurrent to avoid overwhelming the judge endpoint.
162
+ */
163
+ export async function scoreRuns(records, inputFor, opts = {}) {
164
+ const concurrency = Math.max(1, opts.concurrency ?? (opts.judge ? 4 : 16));
165
+ const out = new Array(records.length);
166
+ let next = 0;
167
+ async function worker() {
168
+ for (;;) {
169
+ const i = next++;
170
+ if (i >= records.length)
171
+ return;
172
+ const r = records[i];
173
+ const score = await scoreQuality(inputFor(r), opts);
174
+ out[i] = { ...r, qualityScore: score };
175
+ }
176
+ }
177
+ await Promise.all(Array.from({ length: Math.min(concurrency, records.length) }, () => worker()));
178
+ return out;
179
+ }
180
+ //# sourceMappingURL=quality-scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-scorer.js","sourceRoot":"","sources":["../../src/self-tuning/quality-scorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * LLM Self-Tuning — the real-time adaptor (P4).
3
+ *
4
+ * Offline tuning (P0-P3) finds a good STATIC config. This closes the last gap:
5
+ * per-session adaptation from LIVE signals, for the failures a static config
6
+ * can't foresee (design §Phase 4). It maps four session signals to conservative,
7
+ * hot-reloadable adjustments and emits them on the adaptation-signal channel the
8
+ * proxy reads per request:
9
+ *
10
+ * - tool-use failure rate ↑ → escalate this turn to the judge (fusion)
11
+ * - per-turn quality ↓ → escalate this turn to the judge (fusion)
12
+ * - context-window utilization ↑ → converge sooner (lower recon threshold)
13
+ * - RECON no-write streak ↑ → force synthesis / deliver now
14
+ *
15
+ * `computeAdaptation` is pure and returns null when everything is nominal (no
16
+ * signal written → the proxy keeps its startup config). Emission is opt-in
17
+ * (`enabled`, default from UAP_REALTIME_ADAPT) so it can never perturb a session
18
+ * that didn't ask for it.
19
+ */
20
+ import { AdaptationSignal } from '../coordination/adaptation-signal.js';
21
+ import { FlagConfig } from './flags.js';
22
+ /** Live session signals (any subset). Absent fields are treated as nominal. */
23
+ export interface SessionSignals {
24
+ /** Fraction of recent tool calls that failed / were malformed (0-1). */
25
+ toolFailureRate?: number;
26
+ /** Fraction of the context window in use (0-1), e.g. from GET /v1/context. */
27
+ contextUtilization?: number;
28
+ /** Consecutive no-write ("RECON") turns. */
29
+ reconStreak?: number;
30
+ /** Recent per-turn composite quality estimate (0-100). */
31
+ turnQuality?: number;
32
+ }
33
+ /** Breach thresholds. Defaults are conservative — adapt only on a real signal. */
34
+ export interface AdaptationThresholds {
35
+ /** Escalate when tool-failure rate exceeds this. Default 0.35. */
36
+ toolFailureRate?: number;
37
+ /** Converge sooner when context utilization exceeds this. Default 0.85. */
38
+ contextUtilization?: number;
39
+ /** Force synthesis when the no-write streak exceeds this. Default 25. */
40
+ reconStreak?: number;
41
+ /** Escalate when turn quality drops below this. Default 45. */
42
+ turnQualityFloor?: number;
43
+ }
44
+ /**
45
+ * Map live signals + the current config to an adaptation signal, or null when
46
+ * nothing breaches a threshold. Pure and deterministic.
47
+ */
48
+ export declare function computeAdaptation(sessionId: string, signals: SessionSignals, current: FlagConfig, now: number, thresholds?: AdaptationThresholds): AdaptationSignal | null;
49
+ export interface EmitOptions extends AdaptationThresholds {
50
+ /** Explicit master switch. Default: auto-on unless opted out (env/config). */
51
+ enabled?: boolean;
52
+ /** Project dir for the config opt-out check. Default process.cwd(). */
53
+ cwd?: string;
54
+ /** Signal directory override (tests). */
55
+ dir?: string;
56
+ /** "now" in unix seconds (host may lack Date). */
57
+ now?: number;
58
+ }
59
+ /**
60
+ * True when real-time adaptation is enabled. AUTO-ON by default; opt out via
61
+ * either `UAP_REALTIME_ADAPT` (0/false/off) or `.uap.json` `realtimeAdapt.enabled:
62
+ * false`. Precedence: explicit arg → env (if set) → config → default(true).
63
+ * The emitter is the effective master switch — with it off, no signal is written
64
+ * so the proxy has nothing to honor, regardless of PROXY_REALTIME_ADAPT.
65
+ */
66
+ export declare function realtimeAdaptEnabled(explicit?: boolean, cwd?: string): boolean;
67
+ /**
68
+ * Compute + emit an adaptation signal for a session. No-op (returns null) when
69
+ * disabled or when nothing breaches a threshold. Never throws.
70
+ */
71
+ export declare function emitAdaptation(sessionId: string, signals: SessionSignals, current: FlagConfig, opts?: EmitOptions): AdaptationSignal | null;
72
+ /**
73
+ * Best-effort read of the proxy's per-session context state (GET /v1/context) to
74
+ * populate `contextUtilization`. Injectable fetch for tests. Returns {} on any
75
+ * failure (the adaptor treats missing signals as nominal).
76
+ */
77
+ export declare function fetchSessionContext(endpoint?: string, fetchImpl?: typeof fetch): Promise<Pick<SessionSignals, 'contextUtilization'>>;
78
+ //# sourceMappingURL=realtime-adaptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-adaptor.d.ts","sourceRoot":"","sources":["../../src/self-tuning/realtime-adaptor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,gBAAgB,EAEjB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AAEnD,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AASD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,oBAAyB,GACpC,gBAAgB,GAAG,IAAI,CAiCzB;AAED,MAAM,WAAW,WAAY,SAAQ,oBAAoB;IACvD,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAa9E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,UAAU,EACnB,IAAI,GAAE,WAAgB,GACrB,gBAAgB,GAAG,IAAI,CAYzB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,oBAAoB,CAAC,CAAC,CAYrD"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * LLM Self-Tuning — the real-time adaptor (P4).
3
+ *
4
+ * Offline tuning (P0-P3) finds a good STATIC config. This closes the last gap:
5
+ * per-session adaptation from LIVE signals, for the failures a static config
6
+ * can't foresee (design §Phase 4). It maps four session signals to conservative,
7
+ * hot-reloadable adjustments and emits them on the adaptation-signal channel the
8
+ * proxy reads per request:
9
+ *
10
+ * - tool-use failure rate ↑ → escalate this turn to the judge (fusion)
11
+ * - per-turn quality ↓ → escalate this turn to the judge (fusion)
12
+ * - context-window utilization ↑ → converge sooner (lower recon threshold)
13
+ * - RECON no-write streak ↑ → force synthesis / deliver now
14
+ *
15
+ * `computeAdaptation` is pure and returns null when everything is nominal (no
16
+ * signal written → the proxy keeps its startup config). Emission is opt-in
17
+ * (`enabled`, default from UAP_REALTIME_ADAPT) so it can never perturb a session
18
+ * that didn't ask for it.
19
+ */
20
+ import { writeAdaptationSignal, } from '../coordination/adaptation-signal.js';
21
+ import { loadUapConfigRaw } from '../utils/config-loader.js';
22
+ import { flagValue } from './flags.js';
23
+ const DEFAULTS = {
24
+ toolFailureRate: 0.35,
25
+ contextUtilization: 0.85,
26
+ reconStreak: 25,
27
+ turnQualityFloor: 45,
28
+ };
29
+ /**
30
+ * Map live signals + the current config to an adaptation signal, or null when
31
+ * nothing breaches a threshold. Pure and deterministic.
32
+ */
33
+ export function computeAdaptation(sessionId, signals, current, now, thresholds = {}) {
34
+ const thr = { ...DEFAULTS, ...thresholds };
35
+ const reasons = [];
36
+ const out = { ts: now, sessionId, reason: '' };
37
+ // Quality / reliability degradation → escalate this turn to the judge.
38
+ if (signals.toolFailureRate != null && signals.toolFailureRate > thr.toolFailureRate) {
39
+ out.escalate = true;
40
+ out.recipe = 'fusion';
41
+ reasons.push(`tool-failure ${(signals.toolFailureRate * 100).toFixed(0)}% > ${(thr.toolFailureRate * 100).toFixed(0)}%`);
42
+ }
43
+ if (signals.turnQuality != null && signals.turnQuality < thr.turnQualityFloor) {
44
+ out.escalate = true;
45
+ out.recipe = 'fusion';
46
+ reasons.push(`turn-quality ${signals.turnQuality.toFixed(0)} < ${thr.turnQualityFloor}`);
47
+ }
48
+ // Context pressure → converge sooner (lower the recon threshold live).
49
+ if (signals.contextUtilization != null && signals.contextUtilization > thr.contextUtilization) {
50
+ const cur = Number(flagValue(current, 'PROXY_RECON_CONVERGENCE_THRESHOLD')) || 40;
51
+ out.reconThreshold = Math.max(20, Math.min(cur, Math.round(cur * 0.5)));
52
+ reasons.push(`ctx ${(signals.contextUtilization * 100).toFixed(0)}% > ${(thr.contextUtilization * 100).toFixed(0)}% → recon≤${out.reconThreshold}`);
53
+ }
54
+ // RECON loop → force synthesis / deliver now.
55
+ if (signals.reconStreak != null && signals.reconStreak > thr.reconStreak) {
56
+ out.forceSynthesis = true;
57
+ reasons.push(`recon-streak ${signals.reconStreak} > ${thr.reconStreak}`);
58
+ }
59
+ if (reasons.length === 0)
60
+ return null; // nominal — do not emit
61
+ out.reason = reasons.join('; ');
62
+ return out;
63
+ }
64
+ /**
65
+ * True when real-time adaptation is enabled. AUTO-ON by default; opt out via
66
+ * either `UAP_REALTIME_ADAPT` (0/false/off) or `.uap.json` `realtimeAdapt.enabled:
67
+ * false`. Precedence: explicit arg → env (if set) → config → default(true).
68
+ * The emitter is the effective master switch — with it off, no signal is written
69
+ * so the proxy has nothing to honor, regardless of PROXY_REALTIME_ADAPT.
70
+ */
71
+ export function realtimeAdaptEnabled(explicit, cwd) {
72
+ if (explicit !== undefined)
73
+ return explicit;
74
+ const v = (process.env.UAP_REALTIME_ADAPT ?? '').toLowerCase();
75
+ if (v)
76
+ return v === '1' || v === 'true' || v === 'on' || v === 'yes';
77
+ try {
78
+ const raw = loadUapConfigRaw(cwd ?? process.cwd());
79
+ if (raw?.realtimeAdapt?.enabled === false)
80
+ return false;
81
+ }
82
+ catch {
83
+ /* fall through to default */
84
+ }
85
+ return true; // auto-on
86
+ }
87
+ /**
88
+ * Compute + emit an adaptation signal for a session. No-op (returns null) when
89
+ * disabled or when nothing breaches a threshold. Never throws.
90
+ */
91
+ export function emitAdaptation(sessionId, signals, current, opts = {}) {
92
+ if (!realtimeAdaptEnabled(opts.enabled, opts.cwd))
93
+ return null;
94
+ const now = opts.now ?? Date.now() / 1000;
95
+ const sig = computeAdaptation(sessionId, signals, current, now, opts);
96
+ if (sig) {
97
+ try {
98
+ writeAdaptationSignal(sig, opts.dir);
99
+ }
100
+ catch {
101
+ /* fail open */
102
+ }
103
+ }
104
+ return sig;
105
+ }
106
+ /**
107
+ * Best-effort read of the proxy's per-session context state (GET /v1/context) to
108
+ * populate `contextUtilization`. Injectable fetch for tests. Returns {} on any
109
+ * failure (the adaptor treats missing signals as nominal).
110
+ */
111
+ export async function fetchSessionContext(endpoint, fetchImpl = fetch) {
112
+ const base = (endpoint ?? process.env.UAP_INFERENCE_ENDPOINT ?? 'http://localhost:4000/v1').replace(/\/$/, '');
113
+ try {
114
+ const res = await fetchImpl(`${base}/context`);
115
+ if (!res.ok)
116
+ return {};
117
+ const data = (await res.json());
118
+ let util = data.utilization;
119
+ if (util == null && data.used != null && data.window)
120
+ util = data.used / data.window;
121
+ return util != null ? { contextUtilization: Math.max(0, Math.min(1, util)) } : {};
122
+ }
123
+ catch {
124
+ return {};
125
+ }
126
+ }
127
+ //# sourceMappingURL=realtime-adaptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-adaptor.js","sourceRoot":"","sources":["../../src/self-tuning/realtime-adaptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * LLM Self-Tuning — the autonomous run loop + profile persistence (P2/P3).
3
+ *
4
+ * `runTuningLoop` drives multiple `runTuningIteration` steps under a search-phase
5
+ * schedule (coarse → medium → fine → combinatorial, design §3.3.2), commits each
6
+ * ACCEPTED config to `.uap.json`/`.uap/proxy.env` via the flag-writer (only when
7
+ * `apply` is set), advances the model's versioned `TuningProfile`, and stops on
8
+ * budget exhaustion or a quality plateau (N consecutive rejections). Cross-model
9
+ * bundled/stored profiles seed the optimizer as transfer priors.
10
+ *
11
+ * The `validate` dependency is injected, so the whole loop runs end-to-end in a
12
+ * test with a deterministic stub — no live model required.
13
+ */
14
+ import { FlagConfig } from './flags.js';
15
+ import type { JudgeClient } from './judge.js';
16
+ import type { SearchPhase } from './search-reducer.js';
17
+ import { TunerOptions } from './llm-tuner.js';
18
+ import { TuningValidator, TuningDecisionOptions, TuningIterationResult } from './orchestrator.js';
19
+ import { TuningProfile, TuningProfileStore } from './tuning-profile.js';
20
+ export interface TuningLoopDeps {
21
+ /** Executor model family being tuned. */
22
+ model: string;
23
+ /** The injected paired-bench validator (candidate vs current). */
24
+ validate: TuningValidator;
25
+ /** Judge/tuner model client; null → the GP-BO path. */
26
+ judge?: JudgeClient | null;
27
+ /** Starting config; defaults to the model's seeded profile config. */
28
+ startConfig?: FlagConfig;
29
+ /** Max iterations (token/time budget). Default 6. */
30
+ maxIterations?: number;
31
+ /** Consecutive rejections before declaring a plateau and stopping. Default 3. */
32
+ plateauLimit?: number;
33
+ /** Search-phase schedule (cycled). Default coarse→medium→fine→combinatorial. */
34
+ phaseSchedule?: SearchPhase[];
35
+ decision?: TuningDecisionOptions;
36
+ tuner?: TunerOptions;
37
+ /** Extra transfer priors on top of the cross-model bundled/stored profiles. */
38
+ priors?: FlagConfig[];
39
+ validationSuites?: string[];
40
+ /** Stable timestamp (host may lack Date). */
41
+ now: string;
42
+ /** Physically persist accepted configs + the profile snapshot. */
43
+ apply: boolean;
44
+ /** Project dir for the flag-writer + profile store base. Required when apply. */
45
+ cwd?: string;
46
+ /** Profile store; when omitted, a fresh in-memory profile is used. */
47
+ profileStore?: TuningProfileStore;
48
+ log?: (msg: string) => void;
49
+ }
50
+ export interface TuningLoopResult {
51
+ model: string;
52
+ iterations: TuningIterationResult[];
53
+ accepted: TuningIterationResult[];
54
+ finalConfig: FlagConfig;
55
+ finalQuality: number;
56
+ profile: TuningProfile;
57
+ committed: boolean;
58
+ stoppedBecause: 'budget' | 'plateau';
59
+ }
60
+ export declare function runTuningLoop(deps: TuningLoopDeps): Promise<TuningLoopResult>;
61
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/self-tuning/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EAEtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,aAAa,EACb,kBAAkB,EAInB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,QAAQ,EAAE,eAAe,CAAC;IAC1B,uDAAuD;IACvD,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,sEAAsE;IACtE,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,KAAK,EAAE,OAAO,CAAC;IACf,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,WAAW,EAAE,UAAU,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,QAAQ,GAAG,SAAS,CAAC;CACtC;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkHnF"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * LLM Self-Tuning — the autonomous run loop + profile persistence (P2/P3).
3
+ *
4
+ * `runTuningLoop` drives multiple `runTuningIteration` steps under a search-phase
5
+ * schedule (coarse → medium → fine → combinatorial, design §3.3.2), commits each
6
+ * ACCEPTED config to `.uap.json`/`.uap/proxy.env` via the flag-writer (only when
7
+ * `apply` is set), advances the model's versioned `TuningProfile`, and stops on
8
+ * budget exhaustion or a quality plateau (N consecutive rejections). Cross-model
9
+ * bundled/stored profiles seed the optimizer as transfer priors.
10
+ *
11
+ * The `validate` dependency is injected, so the whole loop runs end-to-end in a
12
+ * test with a deterministic stub — no live model required.
13
+ */
14
+ import { normalizeModel } from '../self-harness/weakness.js';
15
+ import { applyFlagChanges } from './flag-writer.js';
16
+ import { runTuningIteration, } from './orchestrator.js';
17
+ import { crossModelPriors, recordStep, seedProfile, } from './tuning-profile.js';
18
+ const DEFAULT_PHASES = ['coarse', 'medium', 'fine', 'combinatorial'];
19
+ export async function runTuningLoop(deps) {
20
+ const log = deps.log ?? (() => { });
21
+ const maxIter = deps.maxIterations ?? 6;
22
+ const plateauLimit = deps.plateauLimit ?? 3;
23
+ const phases = deps.phaseSchedule ?? DEFAULT_PHASES;
24
+ let profile = deps.profileStore
25
+ ? deps.profileStore.loadOrSeed(deps.model, deps.now)
26
+ : seedProfile(deps.model, deps.now);
27
+ let currentConfig = deps.startConfig ?? { ...profile.config };
28
+ let bestQuality = profile.quality;
29
+ // Observations seed the GP: the profile's accepted history + a synthetic
30
+ // baseline point for the starting config at its recorded quality.
31
+ const observations = [];
32
+ if (bestQuality > 0)
33
+ observations.push({ config: { ...currentConfig }, quality: bestQuality });
34
+ // Cross-model priors (bundled + other stored profiles) for transfer learning.
35
+ const priors = [
36
+ ...crossModelPriors(deps.model, deps.profileStore),
37
+ ...(deps.priors ?? []),
38
+ ];
39
+ const iterations = [];
40
+ const accepted = [];
41
+ let committed = false;
42
+ let plateau = 0;
43
+ let stoppedBecause = 'budget';
44
+ for (let i = 0; i < maxIter; i++) {
45
+ const phase = phases[i % phases.length];
46
+ log(`— iteration ${i + 1}/${maxIter} [${phase}] —`);
47
+ const result = await runTuningIteration({
48
+ ctx: {
49
+ model: normalizeModel(deps.model),
50
+ currentConfig,
51
+ observations: [...observations],
52
+ priors,
53
+ validationSuites: deps.validationSuites,
54
+ },
55
+ validate: deps.validate,
56
+ tuner: { ...deps.tuner, judge: deps.judge },
57
+ decision: deps.decision,
58
+ phase,
59
+ log,
60
+ });
61
+ iterations.push(result);
62
+ if (result.observation)
63
+ observations.push(result.observation);
64
+ if (result.accepted && result.decision) {
65
+ accepted.push(result);
66
+ plateau = 0;
67
+ const q = result.observation?.quality ?? bestQuality + result.decision.qualityDelta;
68
+ bestQuality = Math.max(bestQuality, q);
69
+ currentConfig = result.config;
70
+ // Commit: persist the accepted flag changes + advance the profile.
71
+ if (deps.apply) {
72
+ if (!deps.cwd)
73
+ throw new Error('runTuningLoop: apply set but no cwd for the flag-writer');
74
+ const res = applyFlagChanges(deps.cwd, result.proposal.changes);
75
+ if (res.skipped.length)
76
+ log(` (skipped ${res.skipped.length} change(s) on commit)`);
77
+ committed = true;
78
+ }
79
+ profile = recordStep(profile, {
80
+ at: deps.now,
81
+ changes: result.proposal.changes,
82
+ quality: q,
83
+ delta: result.decision.qualityDelta,
84
+ accepted: true,
85
+ provenance: `tune ${phase} via ${result.proposal.source}`,
86
+ }, currentConfig);
87
+ if (deps.apply && deps.profileStore)
88
+ deps.profileStore.save(profile);
89
+ }
90
+ else {
91
+ plateau++;
92
+ if (result.decision) {
93
+ profile = recordStep(profile, {
94
+ at: deps.now,
95
+ changes: result.proposal.changes,
96
+ quality: result.observation?.quality ?? NaN,
97
+ delta: result.decision.qualityDelta,
98
+ accepted: false,
99
+ provenance: `tune ${phase} via ${result.proposal.source} (rejected)`,
100
+ }, currentConfig);
101
+ }
102
+ if (plateau >= plateauLimit) {
103
+ stoppedBecause = 'plateau';
104
+ log(`plateau: ${plateau} consecutive non-accepts — stopping`);
105
+ break;
106
+ }
107
+ }
108
+ }
109
+ if (deps.apply && deps.profileStore)
110
+ deps.profileStore.save(profile);
111
+ return {
112
+ model: normalizeModel(deps.model),
113
+ iterations,
114
+ accepted,
115
+ finalConfig: currentConfig,
116
+ finalQuality: bestQuality,
117
+ profile,
118
+ committed,
119
+ stoppedBecause,
120
+ };
121
+ }
122
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/self-tuning/run.ts"],"names":[],"mappings":"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"}