opencode-agent-skill 13.0.0-beta.1 → 14.2.0-beta.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.
- package/README.md +1557 -606
- package/bin/ocskill.mjs +172 -24
- package/docs/OPENCODE-COMPAT.md +34 -95
- package/docs/PI-COMPAT.md +188 -0
- package/docs/V14-CONTEXT-MEMORY-FABRIC.md +70 -0
- package/docs/V14.1-QUALITY-PERFORMANCE-FABRIC.md +114 -0
- package/docs/V14.2-TURBO-WEAK-MODEL-RUNTIME.md +448 -0
- package/evals/v14/tasks.json +46 -0
- package/global-config/agents/executor.md +7 -0
- package/global-config/agents/visual-verifier.md +22 -3
- package/global-config/commands/run.md +27 -20
- package/global-config/plugins/ues-router/command-runtime.js +54 -0
- package/global-config/plugins/ues-router/index.js +30 -24
- package/global-config/plugins/ues-router/policy-runtime.js +7 -0
- package/global-config/plugins/ues-router/router.js +12 -2
- package/global-config/skills/ecommerce-engineering/SKILL.md +1 -1
- package/global-config/skills/file-upload-engineering/SKILL.md +1 -1
- package/global-config/skills/git-safety/SKILL.md +1 -1
- package/global-config/skills/nestjs-engineering/SKILL.md +1 -1
- package/global-config/skills/performance-engineering/SKILL.md +1 -1
- package/global-config/skills/react-native-engineering/SKILL.md +1 -1
- package/global-config/skills/rest-api-design/SKILL.md +1 -1
- package/global-config/skills/ui-ux-engineering/SKILL.md +1 -1
- package/lib/adaptive-context-budget.mjs +97 -0
- package/lib/affected-tests.mjs +260 -0
- package/lib/benchmark-confidence.mjs +41 -2
- package/lib/browser-mcp-routing.mjs +166 -0
- package/lib/capability-fabric.mjs +336 -0
- package/lib/capability-registry.mjs +9 -0
- package/lib/context-engine-v11.mjs +65 -1
- package/lib/context-graph-rank.mjs +118 -0
- package/lib/context-manifest.mjs +97 -18
- package/lib/control-center.mjs +19 -1
- package/lib/dynamic-workflow.mjs +3 -1
- package/lib/evidence-store.mjs +82 -1
- package/lib/hierarchical-context.mjs +215 -0
- package/lib/memory-engine.mjs +465 -0
- package/lib/model-performance.mjs +33 -8
- package/lib/model-policy.mjs +3 -3
- package/lib/orchestrator-policy.mjs +5 -209
- package/lib/performance-fabric.mjs +229 -0
- package/lib/pi-rpc-pool.mjs +433 -0
- package/lib/process-hang-detector.mjs +83 -0
- package/lib/process-supervisor.mjs +193 -0
- package/lib/prompt-cache.mjs +2 -0
- package/lib/repo-graph.mjs +53 -2
- package/lib/runtime-config.mjs +31 -0
- package/lib/safety.mjs +132 -0
- package/lib/semantic-index.mjs +52 -3
- package/lib/skill-compiler.mjs +128 -0
- package/lib/skill-quality.mjs +48 -2
- package/lib/task-engine.mjs +66 -5
- package/lib/task-policy.mjs +235 -0
- package/lib/verification-broker.mjs +284 -0
- package/lib/verification-command.mjs +111 -0
- package/lib/windows-shim.mjs +35 -0
- package/lib/workspace-fingerprint.mjs +198 -0
- package/package.json +52 -42
- package/pi/extensions/ues-child-runtime.ts +238 -0
- package/pi/extensions/ues.ts +3200 -0
- package/pi/prompts/ues-audit.md +9 -0
- package/pi/prompts/ues-critique.md +9 -0
- package/pi/prompts/ues-debug.md +9 -0
- package/pi/prompts/ues-feature.md +9 -0
- package/pi/prompts/ues-fix.md +9 -0
- package/pi/prompts/ues-plan.md +9 -0
- package/pi/prompts/ues-research.md +9 -0
- package/pi/prompts/ues-resume.md +9 -0
- package/pi/prompts/ues-review.md +7 -0
- package/pi/prompts/ues-run.md +17 -0
- package/pi/prompts/ues-verify.md +9 -0
- package/scripts/check-release-consistency.mjs +119 -185
- package/scripts/check-runtime-exports.mjs +66 -0
- package/scripts/check-source-integrity.mjs +184 -0
- package/scripts/eval-pi.mjs +492 -0
- package/scripts/install.mjs +16 -0
- package/scripts/smoke-package-closure.mjs +110 -0
- package/scripts/smoke-packed-install.mjs +24 -11
- package/scripts/smoke-pi-extension.mjs +144 -0
- package/scripts/uninstall.mjs +44 -0
- package/CHANGELOG.md +0 -405
- package/docs/DETERMINISTIC-TOOLS.md +0 -105
- package/docs/ENGINEERING-DESIGN.md +0 -194
- package/docs/EVALS.md +0 -158
- package/docs/GITHUB-RULESET.md +0 -50
- package/docs/NPM-PUBLISH.md +0 -116
- package/docs/RESEARCH-SOURCES.md +0 -37
- package/docs/TRACE-SCHEMA.md +0 -122
- package/docs/V11-PERCEPTION-ADAPTIVE-EXECUTION.md +0 -75
- package/docs/V11-PERCEPTION-ADAPTIVE.md +0 -220
- package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +0 -27
- package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +0 -75
- package/docs/V7-INTELLIGENCE-RUNTIME.md +0 -166
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +0 -206
- package/docs/V9-SPEED-INTELLIGENCE.md +0 -102
|
@@ -125,8 +125,36 @@ export function pairedBenchmarkConfidence(results, options = {}) {
|
|
|
125
125
|
initialInputAcceptable,
|
|
126
126
|
tokensAcceptable,
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
const baselineContaminated = pairs.filter((pair) => pair.baseline?.baselineIsolated === false).length
|
|
130
|
+
const baselineIsolationUnknown = pairs.filter((pair) => pair.baseline?.baselineIsolated !== true).length - baselineContaminated
|
|
131
|
+
const uesControllerUnproven = pairs.filter((pair) => pair.ues?.telemetry?.controllerUsed !== true).length
|
|
132
|
+
const uesFalsePasses = pairs.filter((pair) =>
|
|
133
|
+
pair.ues?.telemetry?.controllerPass === true &&
|
|
134
|
+
Number(pair.ues?.graderExit) !== 0
|
|
135
|
+
).length
|
|
136
|
+
const qualityRegressionTolerance = Math.max(0, Number(options.qualityRegressionTolerance || 0))
|
|
137
|
+
const qualityNonRegression = delta >= -qualityRegressionTolerance
|
|
138
|
+
const efficiencySignals = [
|
|
139
|
+
durationRatio == null ? null : durationRatio < 1,
|
|
140
|
+
initialInputRatio == null ? null : initialInputRatio < 1,
|
|
141
|
+
tokenRatio == null ? null : tokenRatio < 1,
|
|
142
|
+
].filter((value) => value !== null)
|
|
143
|
+
const efficiencyImproved = efficiencySignals.some(Boolean)
|
|
144
|
+
const turboChecks = {
|
|
145
|
+
pairedCoverage: total >= minPairs,
|
|
146
|
+
baselineIsolated: baselineContaminated === 0 && baselineIsolationUnknown === 0,
|
|
147
|
+
uesControllerUsed: uesControllerUnproven === 0,
|
|
148
|
+
qualityNonRegression,
|
|
149
|
+
noSuiteRegression,
|
|
150
|
+
noControllerFalsePass: uesFalsePasses === 0,
|
|
151
|
+
speedAcceptable,
|
|
152
|
+
initialInputAcceptable,
|
|
153
|
+
tokensAcceptable,
|
|
154
|
+
efficiencyImproved,
|
|
155
|
+
}
|
|
128
156
|
return {
|
|
129
|
-
schemaVersion:
|
|
157
|
+
schemaVersion: 3,
|
|
130
158
|
kind: "ues-paired-benchmark-confidence",
|
|
131
159
|
pairs: total,
|
|
132
160
|
bothPass,
|
|
@@ -169,5 +197,16 @@ export function pairedBenchmarkConfidence(results, options = {}) {
|
|
|
169
197
|
suites,
|
|
170
198
|
checks,
|
|
171
199
|
promotionEligible: Object.values(checks).every(Boolean),
|
|
200
|
+
turbo: {
|
|
201
|
+
policy: "quality-non-regression-with-efficiency-gain",
|
|
202
|
+
qualityRegressionTolerance,
|
|
203
|
+
baselineContaminated,
|
|
204
|
+
baselineIsolationUnknown,
|
|
205
|
+
uesControllerUnproven,
|
|
206
|
+
uesFalsePasses,
|
|
207
|
+
efficiencyImproved,
|
|
208
|
+
checks: turboChecks,
|
|
209
|
+
promotionEligible: Object.values(turboChecks).every(Boolean),
|
|
210
|
+
},
|
|
172
211
|
}
|
|
173
|
-
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { inferTaskCapabilities } from "./capability-registry.mjs"
|
|
2
|
+
|
|
3
|
+
const BROWSER_ROLES = new Set([
|
|
4
|
+
"executor",
|
|
5
|
+
"debugger",
|
|
6
|
+
"verifier",
|
|
7
|
+
"integration-verifier",
|
|
8
|
+
"visual-verifier",
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
const VISUAL_SIGNAL =
|
|
12
|
+
/(visual fidelity|visual regression|screenshot|figma|pixel|layout|responsive|viewport|accessibility snapshot|giao diện|\bui\b|\bcss\b|styling|kiểm tra hiển thị)/i
|
|
13
|
+
|
|
14
|
+
const PROVIDER_SIGNAL =
|
|
15
|
+
/(playwright|browser automation|browser mcp|chromium|webkit|firefox)/i
|
|
16
|
+
|
|
17
|
+
const BROWSER_TOOL_NAME =
|
|
18
|
+
/(^|[_:.])(browser|playwright)([_:.]|$)|^browser_|^playwright_|mcp.*(?:browser|playwright)/i
|
|
19
|
+
|
|
20
|
+
const ACTION_PRIORITY = [
|
|
21
|
+
["snapshot", 18],
|
|
22
|
+
["screenshot", 17],
|
|
23
|
+
["console", 16],
|
|
24
|
+
["network", 15],
|
|
25
|
+
["navigate", 14],
|
|
26
|
+
["viewport", 13],
|
|
27
|
+
["click", 12],
|
|
28
|
+
["fill", 11],
|
|
29
|
+
["type", 10],
|
|
30
|
+
["select", 9],
|
|
31
|
+
["press", 8],
|
|
32
|
+
["wait", 7],
|
|
33
|
+
["hover", 6],
|
|
34
|
+
["locator", 5],
|
|
35
|
+
["evaluate", 4],
|
|
36
|
+
["close", 1],
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
const BLOCKED_BUILTINS = new Set([
|
|
40
|
+
"read",
|
|
41
|
+
"grep",
|
|
42
|
+
"find",
|
|
43
|
+
"ls",
|
|
44
|
+
"bash",
|
|
45
|
+
"powershell",
|
|
46
|
+
"edit",
|
|
47
|
+
"write",
|
|
48
|
+
"ues_cli",
|
|
49
|
+
"ues_execute",
|
|
50
|
+
"ues_dispatch",
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
function textForTool(tool = {}) {
|
|
54
|
+
return [
|
|
55
|
+
tool.name,
|
|
56
|
+
tool.label,
|
|
57
|
+
tool.description,
|
|
58
|
+
].filter(Boolean).join(" ")
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function normalizeExplicitNames(values = []) {
|
|
62
|
+
if (typeof values === "string") values = values.split(",")
|
|
63
|
+
return [...new Set(
|
|
64
|
+
(Array.isArray(values) ? values : [])
|
|
65
|
+
.map((value) => String(value || "").trim())
|
|
66
|
+
.filter(Boolean),
|
|
67
|
+
)]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function visualEvidenceNeeded(text = "") {
|
|
71
|
+
const value = String(text || "")
|
|
72
|
+
const capabilities = inferTaskCapabilities(value, { coding: true })
|
|
73
|
+
return capabilities.required.vision === true || VISUAL_SIGNAL.test(value)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function browserEvidenceNeeded(text = "", role = "") {
|
|
77
|
+
const normalizedRole = String(role || "").replace(/^ues-/, "")
|
|
78
|
+
if (!BROWSER_ROLES.has(normalizedRole)) return false
|
|
79
|
+
if (normalizedRole === "visual-verifier") return true
|
|
80
|
+
|
|
81
|
+
const capabilities = inferTaskCapabilities(String(text || ""), { coding: true })
|
|
82
|
+
return (
|
|
83
|
+
capabilities.required.browser === true ||
|
|
84
|
+
capabilities.required.vision === true ||
|
|
85
|
+
VISUAL_SIGNAL.test(String(text || ""))
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function selectBrowserMcpToolNames(tools = [], options = {}) {
|
|
90
|
+
const limit = Math.max(1, Math.min(Number(options.limit || 14), 32))
|
|
91
|
+
const explicit = normalizeExplicitNames(options.explicitNames)
|
|
92
|
+
const rows = []
|
|
93
|
+
const available = new Map()
|
|
94
|
+
|
|
95
|
+
for (const raw of Array.isArray(tools) ? tools : []) {
|
|
96
|
+
const name = String(raw?.name || "").trim()
|
|
97
|
+
if (!name || BLOCKED_BUILTINS.has(name) || name.startsWith("ues_")) continue
|
|
98
|
+
available.set(name, raw)
|
|
99
|
+
|
|
100
|
+
const descriptor = textForTool(raw)
|
|
101
|
+
const providerHit = PROVIDER_SIGNAL.test(descriptor)
|
|
102
|
+
const nameHit = BROWSER_TOOL_NAME.test(name)
|
|
103
|
+
if (!providerHit && !nameHit) continue
|
|
104
|
+
|
|
105
|
+
let score = providerHit ? 100 : 70
|
|
106
|
+
if (/playwright/i.test(descriptor)) score += 30
|
|
107
|
+
if (/^browser_|(?:^|[_:.])browser[_:.]/i.test(name)) score += 20
|
|
108
|
+
for (const [signal, weight] of ACTION_PRIORITY) {
|
|
109
|
+
if (name.toLowerCase().includes(signal)) {
|
|
110
|
+
score += weight
|
|
111
|
+
break
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
rows.push({ name, score })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const selected = []
|
|
118
|
+
for (const name of explicit) {
|
|
119
|
+
if (available.has(name) && !selected.includes(name)) selected.push(name)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const row of rows.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name))) {
|
|
123
|
+
if (selected.length >= limit) break
|
|
124
|
+
if (!selected.includes(row.name)) selected.push(row.name)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return selected.slice(0, limit)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function selectBrowserToolsForTask(names = [], text = "", role = "") {
|
|
131
|
+
const value = String(text || "").toLowerCase()
|
|
132
|
+
const normalizedRole = String(role || "").replace(/^ues-/, "")
|
|
133
|
+
const visual = visualEvidenceNeeded(text) || normalizedRole === "visual-verifier"
|
|
134
|
+
const interactive = /(click|fill|type|select|press|submit|login|checkout|flow|interaction|form|navigate|đăng nhập|nhấn|điền|chọn)/i.test(value)
|
|
135
|
+
const diagnostics = /(console|network|request|response|error|failed|api|socket|log)/i.test(value)
|
|
136
|
+
|
|
137
|
+
const keep = []
|
|
138
|
+
const addIf = (name, predicate) => {
|
|
139
|
+
const lower = name.toLowerCase()
|
|
140
|
+
if (predicate(lower) && !keep.includes(name)) keep.push(name)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (const name of names) {
|
|
144
|
+
addIf(name, (lower) => /snapshot|accessibility|navigate|close/.test(lower))
|
|
145
|
+
}
|
|
146
|
+
if (visual) {
|
|
147
|
+
for (const name of names) addIf(name, (lower) => /screenshot|viewport|snapshot|accessibility/.test(lower))
|
|
148
|
+
}
|
|
149
|
+
if (interactive) {
|
|
150
|
+
for (const name of names) addIf(name, (lower) => /click|fill|type|select|press|wait|hover|locator|navigate/.test(lower))
|
|
151
|
+
}
|
|
152
|
+
if (diagnostics || normalizedRole === "verifier" || normalizedRole === "integration-verifier") {
|
|
153
|
+
for (const name of names) addIf(name, (lower) => /console|network|request|response/.test(lower))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Keep a small escape hatch for providers whose naming does not expose action semantics.
|
|
157
|
+
if (keep.length < 3) {
|
|
158
|
+
for (const name of names) {
|
|
159
|
+
if (!keep.includes(name)) keep.push(name)
|
|
160
|
+
if (keep.length >= Math.min(6, names.length)) break
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const limit = visual || interactive ? 10 : 6
|
|
165
|
+
return keep.slice(0, limit)
|
|
166
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
|
|
6
|
+
const HEALTH_WEIGHT = { healthy: 40, degraded: 15, unknown: 0, unavailable: -1000 }
|
|
7
|
+
const COST_PENALTY = { low: 0, medium: 5, high: 12 }
|
|
8
|
+
const LATENCY_PENALTY = { fast: 0, medium: 3, slow: 8 }
|
|
9
|
+
const OBSERVATION_FILE = "CAPABILITY-OBSERVATIONS.json"
|
|
10
|
+
|
|
11
|
+
function observationPath(root) {
|
|
12
|
+
return path.join(path.resolve(root), ".ues-learning", OBSERVATION_FILE)
|
|
13
|
+
}
|
|
14
|
+
async function atomicJson(file, value) {
|
|
15
|
+
await mkdir(path.dirname(file), { recursive: true })
|
|
16
|
+
const temp = file + "." + process.pid + "." + Date.now() + ".tmp"
|
|
17
|
+
await writeFile(temp, JSON.stringify(value, null, 2) + "\n", "utf8")
|
|
18
|
+
try { await rename(temp, file) } catch (error) { await rm(temp, { force: true }).catch(() => {}); throw error }
|
|
19
|
+
}
|
|
20
|
+
export async function readCapabilityObservations(root = process.cwd()) {
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(await readFile(observationPath(root), "utf8"))
|
|
23
|
+
return { schemaVersion: 1, updatedAt: parsed.updatedAt || null, capabilities: parsed.capabilities && typeof parsed.capabilities === "object" ? parsed.capabilities : {} }
|
|
24
|
+
} catch { return { schemaVersion: 1, updatedAt: null, capabilities: {} } }
|
|
25
|
+
}
|
|
26
|
+
export async function recordCapabilityObservation(root, capability, providerId, input = {}) {
|
|
27
|
+
if (!capability || !providerId) throw new Error("capability observation requires capability and provider id")
|
|
28
|
+
const state = await readCapabilityObservations(root)
|
|
29
|
+
const previous = state.capabilities?.[capability]?.[providerId] || {}
|
|
30
|
+
const success = input.success === true, failure = input.success === false
|
|
31
|
+
const samples = Number(previous.samples || 0) + (success || failure ? 1 : 0)
|
|
32
|
+
const successes = Number(previous.successes || 0) + (success ? 1 : 0)
|
|
33
|
+
const failures = Number(previous.failures || 0) + (failure ? 1 : 0)
|
|
34
|
+
const latencyMs = Number.isFinite(Number(input.latencyMs)) ? Math.max(0, Number(input.latencyMs)) : null
|
|
35
|
+
const previousLatencySamples = Number(previous.latencySamples || 0)
|
|
36
|
+
const latencySamples = previousLatencySamples + (latencyMs == null ? 0 : 1)
|
|
37
|
+
const avgLatencyMs = latencyMs == null ? (previous.avgLatencyMs ?? null) : ((Number(previous.avgLatencyMs || 0) * previousLatencySamples) + latencyMs) / Math.max(1, latencySamples)
|
|
38
|
+
const next = {
|
|
39
|
+
samples, successes, failures,
|
|
40
|
+
successRate: samples ? successes / samples : 0,
|
|
41
|
+
failureRate: samples ? failures / samples : 0,
|
|
42
|
+
latencySamples, avgLatencyMs: avgLatencyMs == null ? null : Number(avgLatencyMs.toFixed(2)),
|
|
43
|
+
lastLatencyMs: latencyMs, lastObservedAt: new Date().toISOString(),
|
|
44
|
+
lastError: input.error ? String(input.error).slice(0, 500) : null,
|
|
45
|
+
}
|
|
46
|
+
const capabilities = { ...state.capabilities, [capability]: { ...(state.capabilities?.[capability] || {}), [providerId]: next } }
|
|
47
|
+
await atomicJson(observationPath(root), { schemaVersion: 1, updatedAt: next.lastObservedAt, capabilities })
|
|
48
|
+
return next
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function clamp(value, min = 0, max = 1, fallback = 0) {
|
|
52
|
+
const number = Number(value)
|
|
53
|
+
return Number.isFinite(number) ? Math.max(min, Math.min(max, number)) : fallback
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const COMMAND_PROBE_TTL_MS = 60_000
|
|
57
|
+
const commandProbeCache = new Map()
|
|
58
|
+
|
|
59
|
+
function commandExists(command) {
|
|
60
|
+
if (!command) return false
|
|
61
|
+
const now = Date.now()
|
|
62
|
+
const cached = commandProbeCache.get(command)
|
|
63
|
+
if (cached && now - cached.checkedAt < COMMAND_PROBE_TTL_MS) return cached.available
|
|
64
|
+
const finder = process.platform === "win32" ? "where" : "which"
|
|
65
|
+
const result = spawnSync(finder, [command], { stdio: "ignore", windowsHide: true })
|
|
66
|
+
const available = result.status === 0
|
|
67
|
+
commandProbeCache.set(command, { available, checkedAt: now })
|
|
68
|
+
return available
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function packageDeclared(root, name) {
|
|
72
|
+
try {
|
|
73
|
+
const pkg = JSON.parse(await readFile(path.join(root, "package.json"), "utf8"))
|
|
74
|
+
return Boolean(
|
|
75
|
+
pkg.dependencies?.[name] ||
|
|
76
|
+
pkg.devDependencies?.[name] ||
|
|
77
|
+
pkg.optionalDependencies?.[name] ||
|
|
78
|
+
pkg.peerDependencies?.[name],
|
|
79
|
+
)
|
|
80
|
+
} catch {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function normalizeProvider(provider = {}, index = 0) {
|
|
86
|
+
return {
|
|
87
|
+
id: String(provider.id || `provider-${index + 1}`),
|
|
88
|
+
kind: provider.kind || "builtin",
|
|
89
|
+
capability: provider.capability || null,
|
|
90
|
+
priority: Number.isFinite(Number(provider.priority)) ? Number(provider.priority) : 50,
|
|
91
|
+
quality: clamp(provider.quality, 0, 1, 0.5),
|
|
92
|
+
costClass: ["low", "medium", "high"].includes(provider.costClass) ? provider.costClass : "medium",
|
|
93
|
+
latencyClass: ["fast", "medium", "slow"].includes(provider.latencyClass) ? provider.latencyClass : "medium",
|
|
94
|
+
command: provider.command || null,
|
|
95
|
+
path: provider.path || null,
|
|
96
|
+
package: provider.package || null,
|
|
97
|
+
metadata: provider.metadata || {},
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function defaultCapabilityRegistry(root = process.cwd()) {
|
|
102
|
+
return {
|
|
103
|
+
schemaVersion: 1,
|
|
104
|
+
root: path.resolve(root),
|
|
105
|
+
capabilities: {
|
|
106
|
+
"code.search": [
|
|
107
|
+
{ id: "ues-semantic-index", kind: "builtin", priority: 100, quality: 0.9, costClass: "low", latencyClass: "fast" },
|
|
108
|
+
],
|
|
109
|
+
memory: [
|
|
110
|
+
{ id: "ues-memory", kind: "builtin", priority: 100, quality: 0.9, costClass: "low", latencyClass: "fast" },
|
|
111
|
+
],
|
|
112
|
+
evidence: [
|
|
113
|
+
{ id: "ues-evidence-store", kind: "builtin", priority: 100, quality: 0.95, costClass: "low", latencyClass: "fast" },
|
|
114
|
+
],
|
|
115
|
+
"output.compaction": [
|
|
116
|
+
{
|
|
117
|
+
id: "ues-reversible-compactor",
|
|
118
|
+
kind: "builtin",
|
|
119
|
+
priority: 100,
|
|
120
|
+
quality: 0.98,
|
|
121
|
+
costClass: "low",
|
|
122
|
+
latencyClass: "fast",
|
|
123
|
+
metadata: { default: true, reversible: true, lossy: false, scope: "model-visible UES output" },
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "rtk-cli",
|
|
127
|
+
kind: "command",
|
|
128
|
+
command: "rtk",
|
|
129
|
+
priority: 82,
|
|
130
|
+
quality: 0.9,
|
|
131
|
+
costClass: "low",
|
|
132
|
+
latencyClass: "fast",
|
|
133
|
+
metadata: { default: false, external: true, experimental: false, scope: "shell-output", upstream: "rtk-ai/rtk" },
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "caveman-cli",
|
|
137
|
+
kind: "command",
|
|
138
|
+
command: "caveman",
|
|
139
|
+
priority: 55,
|
|
140
|
+
quality: 0.82,
|
|
141
|
+
costClass: "medium",
|
|
142
|
+
latencyClass: "medium",
|
|
143
|
+
metadata: {
|
|
144
|
+
default: false,
|
|
145
|
+
external: true,
|
|
146
|
+
experimental: true,
|
|
147
|
+
reversible: true,
|
|
148
|
+
upstream: "JuliusBrussee/caveman",
|
|
149
|
+
licenseNote: "External runtime includes BSL-1.1 engine components; do not vendor them into the MIT core.",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: "headroom-cli",
|
|
154
|
+
kind: "command",
|
|
155
|
+
command: "headroom",
|
|
156
|
+
priority: 50,
|
|
157
|
+
quality: 0.82,
|
|
158
|
+
costClass: "medium",
|
|
159
|
+
latencyClass: "medium",
|
|
160
|
+
metadata: {
|
|
161
|
+
default: false,
|
|
162
|
+
external: true,
|
|
163
|
+
experimental: true,
|
|
164
|
+
reversible: true,
|
|
165
|
+
outputShaper: false,
|
|
166
|
+
upstream: "headroomlabs-ai/headroom",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
filesystem: [
|
|
171
|
+
{ id: "node-fs", kind: "builtin", priority: 100, quality: 0.95, costClass: "low", latencyClass: "fast" },
|
|
172
|
+
],
|
|
173
|
+
git: [
|
|
174
|
+
{ id: "git-cli", kind: "command", command: "git", priority: 100, quality: 0.95, costClass: "low", latencyClass: "fast" },
|
|
175
|
+
],
|
|
176
|
+
"agent.host": [
|
|
177
|
+
{ id: "pi-cli", kind: "command", command: "pi", priority: 100, quality: 0.95, costClass: "low", latencyClass: "fast" },
|
|
178
|
+
],
|
|
179
|
+
github: [
|
|
180
|
+
{ id: "gh-cli", kind: "command", command: "gh", priority: 80, quality: 0.85, costClass: "low", latencyClass: "fast" },
|
|
181
|
+
],
|
|
182
|
+
browser: [
|
|
183
|
+
{ id: "project-playwright", kind: "package", package: "playwright", priority: 90, quality: 0.9, costClass: "medium", latencyClass: "medium" },
|
|
184
|
+
{ id: "project-playwright-core", kind: "package", package: "playwright-core", priority: 70, quality: 0.75, costClass: "medium", latencyClass: "medium" },
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function readCapabilityConfig(root, file) {
|
|
191
|
+
const target = file
|
|
192
|
+
? path.resolve(file)
|
|
193
|
+
: process.env.UES_CAPABILITY_CONFIG
|
|
194
|
+
? path.resolve(process.env.UES_CAPABILITY_CONFIG)
|
|
195
|
+
: path.join(path.resolve(root), ".ues-capabilities.json")
|
|
196
|
+
if (!existsSync(target)) return null
|
|
197
|
+
try {
|
|
198
|
+
const parsed = JSON.parse(await readFile(target, "utf8"))
|
|
199
|
+
return parsed && typeof parsed === "object" ? parsed : null
|
|
200
|
+
} catch {
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function mergeRegistry(base, extra) {
|
|
206
|
+
if (!extra?.capabilities || typeof extra.capabilities !== "object") return base
|
|
207
|
+
const capabilities = { ...base.capabilities }
|
|
208
|
+
for (const [name, values] of Object.entries(extra.capabilities)) {
|
|
209
|
+
const custom = Array.isArray(values) ? values : []
|
|
210
|
+
const seen = new Set(custom.map((item) => item?.id).filter(Boolean))
|
|
211
|
+
const inherited = (capabilities[name] || []).filter((item) => !seen.has(item.id))
|
|
212
|
+
capabilities[name] = [...custom, ...inherited]
|
|
213
|
+
}
|
|
214
|
+
return { ...base, capabilities }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export async function loadCapabilityRegistry(root = process.cwd(), options = {}) {
|
|
218
|
+
root = path.resolve(root)
|
|
219
|
+
const base = options.registry || defaultCapabilityRegistry(root)
|
|
220
|
+
if (options.registry) return base
|
|
221
|
+
return mergeRegistry(base, await readCapabilityConfig(root, options.configFile))
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export async function probeCapabilityProvider(provider, root = process.cwd()) {
|
|
225
|
+
const normalized = normalizeProvider(provider)
|
|
226
|
+
const checkedAt = new Date().toISOString()
|
|
227
|
+
if (normalized.kind === "builtin") {
|
|
228
|
+
return { ...normalized, status: "healthy", reason: "built-in", checkedAt }
|
|
229
|
+
}
|
|
230
|
+
if (normalized.kind === "command") {
|
|
231
|
+
const available = commandExists(normalized.command)
|
|
232
|
+
return {
|
|
233
|
+
...normalized,
|
|
234
|
+
status: available ? "healthy" : "unavailable",
|
|
235
|
+
reason: available ? `command:${normalized.command}` : `missing-command:${normalized.command}`,
|
|
236
|
+
checkedAt,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (normalized.kind === "path") {
|
|
240
|
+
const target = normalized.path ? path.resolve(root, normalized.path) : null
|
|
241
|
+
const available = Boolean(target && existsSync(target))
|
|
242
|
+
return {
|
|
243
|
+
...normalized,
|
|
244
|
+
status: available ? "healthy" : "unavailable",
|
|
245
|
+
reason: available ? `path:${normalized.path}` : `missing-path:${normalized.path || ""}`,
|
|
246
|
+
checkedAt,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (normalized.kind === "package") {
|
|
250
|
+
const declared = normalized.package ? await packageDeclared(root, normalized.package) : false
|
|
251
|
+
const installed = normalized.package
|
|
252
|
+
? existsSync(path.join(root, "node_modules", normalized.package))
|
|
253
|
+
: false
|
|
254
|
+
const available = installed || declared
|
|
255
|
+
return {
|
|
256
|
+
...normalized,
|
|
257
|
+
status: installed ? "healthy" : declared ? "degraded" : "unavailable",
|
|
258
|
+
reason: installed
|
|
259
|
+
? `installed-package:${normalized.package}`
|
|
260
|
+
: declared
|
|
261
|
+
? `declared-package:${normalized.package}`
|
|
262
|
+
: `missing-package:${normalized.package || ""}`,
|
|
263
|
+
checkedAt,
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return { ...normalized, status: "unknown", reason: `unknown-kind:${normalized.kind}`, checkedAt }
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function selectCapabilityProvider(capability, providers = [], options = {}) {
|
|
270
|
+
const observations = options.observations || {}
|
|
271
|
+
const allowUnknown = options.allowUnknown === true
|
|
272
|
+
const rows = providers.map((provider, index) => {
|
|
273
|
+
const normalized = normalizeProvider(provider, index)
|
|
274
|
+
const status = provider.status || "unknown"
|
|
275
|
+
const observation = observations[normalized.id] || {}
|
|
276
|
+
const failureRate = clamp(observation.failureRate, 0, 1, 0)
|
|
277
|
+
const successRate = clamp(observation.successRate, 0, 1, 0)
|
|
278
|
+
const samples = Math.max(0, Number(observation.samples || 0))
|
|
279
|
+
const observationConfidence = samples > 0 ? Math.min(1, samples / 5) : 0
|
|
280
|
+
const successBoost = successRate * 12 * observationConfidence
|
|
281
|
+
const failurePenalty = failureRate * 35 * observationConfidence
|
|
282
|
+
const healthWeight = HEALTH_WEIGHT[status] ?? HEALTH_WEIGHT.unknown
|
|
283
|
+
const eligible = status === "healthy" || status === "degraded" || (allowUnknown && status === "unknown")
|
|
284
|
+
const score =
|
|
285
|
+
normalized.priority +
|
|
286
|
+
normalized.quality * 20 +
|
|
287
|
+
successBoost +
|
|
288
|
+
healthWeight -
|
|
289
|
+
(COST_PENALTY[normalized.costClass] ?? 5) -
|
|
290
|
+
(LATENCY_PENALTY[normalized.latencyClass] ?? 3) -
|
|
291
|
+
failurePenalty
|
|
292
|
+
return { ...normalized, status, eligible, samples, successRate, failureRate, observationConfidence: Number(observationConfidence.toFixed(3)), score: Number(score.toFixed(3)), reason: provider.reason || null }
|
|
293
|
+
})
|
|
294
|
+
const eligible = rows.filter((item) => item.eligible).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id))
|
|
295
|
+
return {
|
|
296
|
+
schemaVersion: 1,
|
|
297
|
+
capability,
|
|
298
|
+
selected: eligible[0] || null,
|
|
299
|
+
fallbacks: eligible.slice(1),
|
|
300
|
+
candidates: rows.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)),
|
|
301
|
+
fallbackNeeded: eligible.length === 0,
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export async function capabilityFabricStatus(root = process.cwd(), options = {}) {
|
|
306
|
+
root = path.resolve(root)
|
|
307
|
+
const registry = await loadCapabilityRegistry(root, options)
|
|
308
|
+
const persistedObservations = options.observations ? null : await readCapabilityObservations(root)
|
|
309
|
+
const capabilities = {}
|
|
310
|
+
const rows = []
|
|
311
|
+
for (const [name, providers] of Object.entries(registry.capabilities || {})) {
|
|
312
|
+
const probed = []
|
|
313
|
+
for (const provider of providers || []) probed.push(await probeCapabilityProvider(provider, root))
|
|
314
|
+
const selected = selectCapabilityProvider(name, probed, {
|
|
315
|
+
observations: options.observations?.[name] || persistedObservations?.capabilities?.[name] || {},
|
|
316
|
+
allowUnknown: options.allowUnknown,
|
|
317
|
+
})
|
|
318
|
+
capabilities[name] = selected
|
|
319
|
+
rows.push({
|
|
320
|
+
capability: name,
|
|
321
|
+
selected: selected.selected?.id || null,
|
|
322
|
+
status: selected.selected?.status || "unavailable",
|
|
323
|
+
fallbacks: selected.fallbacks.map((item) => item.id),
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
schemaVersion: 1,
|
|
328
|
+
root,
|
|
329
|
+
generatedAt: new Date().toISOString(),
|
|
330
|
+
rows,
|
|
331
|
+
capabilities,
|
|
332
|
+
healthyCapabilities: rows.filter((item) => item.selected).length,
|
|
333
|
+
totalCapabilities: rows.length,
|
|
334
|
+
observationState: persistedObservations ? { updatedAt: persistedObservations.updatedAt, capabilities: Object.keys(persistedObservations.capabilities || {}).length } : null,
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -107,3 +107,12 @@ export function modelCandidatesFromPolicy(policy = {}) {
|
|
|
107
107
|
export function roleCapabilityRequirements(role) {
|
|
108
108
|
return { ...(ROLE_REQUIREMENTS[role] || {}) }
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
capabilityFabricStatus,
|
|
114
|
+
defaultCapabilityRegistry,
|
|
115
|
+
loadCapabilityRegistry,
|
|
116
|
+
probeCapabilityProvider,
|
|
117
|
+
selectCapabilityProvider,
|
|
118
|
+
} from "./capability-fabric.mjs"
|
|
@@ -4,6 +4,8 @@ import { putEvidence } from "./evidence-store.mjs"
|
|
|
4
4
|
import { inferTaskCapabilities } from "./capability-registry.mjs"
|
|
5
5
|
import { buildPromptEnvelope, comparePromptEnvelopes } from "./prompt-cache.mjs"
|
|
6
6
|
import { measureContextQuality } from "./context-quality.mjs"
|
|
7
|
+
import { retrieveMemories } from "./memory-engine.mjs"
|
|
8
|
+
import { capabilityFabricStatus } from "./capability-fabric.mjs"
|
|
7
9
|
|
|
8
10
|
function taskText(task = {}) {
|
|
9
11
|
return [
|
|
@@ -14,6 +16,20 @@ function taskText(task = {}) {
|
|
|
14
16
|
].filter(Boolean).join(" ")
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
function taskFilesForMemory(task = {}) {
|
|
20
|
+
const files = task.files
|
|
21
|
+
const values = []
|
|
22
|
+
if (Array.isArray(files)) values.push(...files)
|
|
23
|
+
else if (files && typeof files === "object") {
|
|
24
|
+
for (const value of Object.values(files)) {
|
|
25
|
+
if (Array.isArray(value)) values.push(...value)
|
|
26
|
+
else if (typeof value === "string") values.push(value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(task.requiredFiles)) values.push(...task.requiredFiles)
|
|
30
|
+
return [...new Set(values.filter(Boolean))]
|
|
31
|
+
}
|
|
32
|
+
|
|
17
33
|
function rankExcerpt(item = {}, task = {}) {
|
|
18
34
|
const text = taskText(task).toLowerCase()
|
|
19
35
|
const pathValue = String(item.path || "").toLowerCase()
|
|
@@ -91,6 +107,8 @@ export async function buildAdaptiveTaskContext(root, task, options = {}) {
|
|
|
91
107
|
strategy: options.strategy || policy?.profile?.contextStrategy || "incremental-semantic+git",
|
|
92
108
|
semanticMaxFiles: options.semanticMaxFiles,
|
|
93
109
|
maxFiles: options.maxFiles,
|
|
110
|
+
changedFiles: options.changedFiles,
|
|
111
|
+
workspaceFingerprint: options.workspaceFingerprint,
|
|
94
112
|
})
|
|
95
113
|
|
|
96
114
|
const externalized = await externalizeContextExcerpts(root, manifest, {
|
|
@@ -99,6 +117,24 @@ export async function buildAdaptiveTaskContext(root, task, options = {}) {
|
|
|
99
117
|
inlineChars: options.inlineChars,
|
|
100
118
|
})
|
|
101
119
|
|
|
120
|
+
const memoryRetrieval = await retrieveMemories(root, taskText(task), {
|
|
121
|
+
files: taskFilesForMemory(task),
|
|
122
|
+
limit: options.memoryLimit ?? 6,
|
|
123
|
+
taskClass: options.taskClass || task.type || policy.executionProfile || policy.profile?.name || null,
|
|
124
|
+
touch: options.touchMemories !== false,
|
|
125
|
+
}).catch(() => ({ schemaVersion: 1, query: taskText(task), eligible: 0, results: [] }))
|
|
126
|
+
const memories = memoryRetrieval.results || []
|
|
127
|
+
const fabric = await capabilityFabricStatus(root).catch(() => null)
|
|
128
|
+
const providerHints = (fabric?.rows || [])
|
|
129
|
+
.filter((row) => row.selected)
|
|
130
|
+
.slice(0, 12)
|
|
131
|
+
.map((row) => ({
|
|
132
|
+
capability: row.capability,
|
|
133
|
+
selected: row.selected,
|
|
134
|
+
status: row.status,
|
|
135
|
+
fallbacks: (row.fallbacks || []).slice(0, 3),
|
|
136
|
+
}))
|
|
137
|
+
|
|
102
138
|
const promptEnvelope = buildPromptEnvelope({
|
|
103
139
|
invariants: options.invariants || "evidence-first; scoped edits; fresh verification; no unsupported completion claims",
|
|
104
140
|
role: options.role || "executor",
|
|
@@ -114,6 +150,23 @@ export async function buildAdaptiveTaskContext(root, task, options = {}) {
|
|
|
114
150
|
...(externalized.manifest?.rankedReferences || []).slice(0, 12).map((item) => item.path),
|
|
115
151
|
...(options.evidence || []),
|
|
116
152
|
],
|
|
153
|
+
memories: memories.map((item) => ({
|
|
154
|
+
id: item.id,
|
|
155
|
+
type: item.type,
|
|
156
|
+
scope: item.scope,
|
|
157
|
+
content: item.content,
|
|
158
|
+
confidence: item.confidence,
|
|
159
|
+
files: item.files,
|
|
160
|
+
retrieval: item.retrieval,
|
|
161
|
+
})),
|
|
162
|
+
contextHints: {
|
|
163
|
+
hierarchy: (externalized.manifest?.hierarchy?.scopes || []).slice(0, 6).map((item) => ({
|
|
164
|
+
path: item.path,
|
|
165
|
+
score: item.score,
|
|
166
|
+
l0: item.l0,
|
|
167
|
+
})),
|
|
168
|
+
providers: providerHints,
|
|
169
|
+
},
|
|
117
170
|
recentFailure: options.recentFailure || null,
|
|
118
171
|
nextAction: options.nextAction || null,
|
|
119
172
|
recentMessages: options.recentMessages || [],
|
|
@@ -132,6 +185,17 @@ export async function buildAdaptiveTaskContext(root, task, options = {}) {
|
|
|
132
185
|
evidenceBudget,
|
|
133
186
|
contextManifest: externalized.manifest,
|
|
134
187
|
contextQuality,
|
|
188
|
+
memories,
|
|
189
|
+
memoryRetrieval: {
|
|
190
|
+
schemaVersion: memoryRetrieval.schemaVersion || 1,
|
|
191
|
+
eligible: memoryRetrieval.eligible || 0,
|
|
192
|
+
returned: memories.length,
|
|
193
|
+
},
|
|
194
|
+
capabilityFabric: {
|
|
195
|
+
healthyCapabilities: fabric?.healthyCapabilities || 0,
|
|
196
|
+
totalCapabilities: fabric?.totalCapabilities || 0,
|
|
197
|
+
providers: providerHints,
|
|
198
|
+
},
|
|
135
199
|
evidenceStore: {
|
|
136
200
|
refs: externalized.externalized.length,
|
|
137
201
|
externalizedBytes: externalized.externalizedBytes,
|
|
@@ -147,4 +211,4 @@ export async function buildAdaptiveTaskContext(root, task, options = {}) {
|
|
|
147
211
|
...(cache || {}),
|
|
148
212
|
},
|
|
149
213
|
}
|
|
150
|
-
}
|
|
214
|
+
}
|