refactor(retrieval): remove the Python Qwen stack and the QMD extension entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
505e6ae084
commit
5bb0bdf62f
13 files changed
+10
-1785
No files matched your search
@@ -304,9 +304,6 @@ class Manager:
|
||||
if entry['codex_method'] == 'cli':
|
||||
self.ensure_cli(client, entry)
|
||||
return
|
||||
if entry['codex_method'] == 'qmd':
|
||||
self.ensure_qmd(client, entry)
|
||||
return
|
||||
skill = client == 'codex' and entry['codex_method'] != 'plugin'
|
||||
kind = 'skill' if skill else 'plugin'
|
||||
record = next((r for r in self.state['resources'] if r['client'] == client and r['name'] == entry['name']), None)
|
||||
@@ -417,28 +414,6 @@ class Manager:
|
||||
atomic_write(path, (json.dumps(content, indent=2) + '\n').encode('utf-8'))
|
||||
print('Repaired Caveman Windows hook commands; review the changed hooks in Codex /hooks.')
|
||||
|
||||
def ensure_qmd(self, client, entry):
|
||||
package = entry['codex_source']
|
||||
if package != '@tobilu/qmd':
|
||||
raise ValueError('Invalid QMD package.')
|
||||
record = next((r for r in self.state['resources'] if r['client'] == 'shared' and r['name'] == entry['name']), None)
|
||||
installed = package in self.global_packages()
|
||||
if record is not None:
|
||||
record['clients'] = sorted(set(record.get('clients', ['claude', 'codex'])) | {client})
|
||||
self.save()
|
||||
if record is None and installed and not self.summary:
|
||||
print(f'PASS Preserving pre-existing global package: {package}')
|
||||
if (record is not None or not installed) and (not installed or (self.update and package not in self.updated_packages)):
|
||||
self.command(['npm', 'update' if installed else 'install', '--global', package])
|
||||
self.global_packages().add(package)
|
||||
self.updated_packages.add(package)
|
||||
if record is None:
|
||||
self.state['resources'].append(dict(client='shared', name=entry['name'], kind='qmd', package=package, clients=[client]))
|
||||
self.save()
|
||||
if client == 'claude':
|
||||
entry = dict(entry, codex_method='plugin')
|
||||
self.ensure(client, entry)
|
||||
|
||||
def ensure_mcporter(self, entry, clients):
|
||||
server, url = entry['mcporter_name'], entry['mcporter_url']
|
||||
if not re.fullmatch(r'[a-z0-9-]+', server) or not re.fullmatch(r'https://[^\s]+', url):
|
||||
|
||||
@@ -125,9 +125,7 @@ function Select-ConfiguredPlugins {
|
||||
} else { $false }
|
||||
foreach ($referenceClient in $referenceClients) {
|
||||
$selector = if ($referenceClient -eq 'Claude') { $entry.claude_plugin } else { $entry.codex_plugin }
|
||||
if ($referenceClient -eq 'Codex' -and $entry.codex_method -eq 'qmd') {
|
||||
$found = $found -or ($null -ne (Get-Command qmd -ErrorAction SilentlyContinue))
|
||||
} elseif ($referenceClient -eq 'Codex' -and $entry.codex_method -ne 'plugin') {
|
||||
if ($referenceClient -eq 'Codex' -and $entry.codex_method -ne 'plugin') {
|
||||
$found = $found -or (Test-Path -LiteralPath (Join-Path $HomePath ('.agents/skills/' + $entry.codex_skill))) -or (Test-Path -LiteralPath (Join-Path $HomePath ('.codex/skills/' + $entry.codex_skill)))
|
||||
} else {
|
||||
$idField = if ($referenceClient -eq 'Claude') { 'id' } else { 'pluginId' }
|
||||
|
||||
@@ -161,9 +161,7 @@ select_configured_plugins() {
|
||||
fi
|
||||
for reference_client in "${reference_clients[@]}"; do
|
||||
if [ "$reference_client" = claude ]; then selector=$(plugin_field "$root" "$name" claude_plugin); else selector=$(plugin_field "$root" "$name" codex_plugin); fi
|
||||
if [ "$reference_client" = codex ] && [ "$(plugin_field "$root" "$name" codex_method)" = qmd ]; then
|
||||
command -v qmd >/dev/null 2>&1 && found=true
|
||||
elif [ "$reference_client" = codex ] && [ "$(plugin_field "$root" "$name" codex_method)" != plugin ]; then
|
||||
if [ "$reference_client" = codex ] && [ "$(plugin_field "$root" "$name" codex_method)" != plugin ]; then
|
||||
local skill_name
|
||||
skill_name=$(plugin_field "$root" "$name" codex_skill)
|
||||
{ [ -d "$HOME/.agents/skills/$skill_name" ] || [ -d "$HOME/.codex/skills/$skill_name" ]; } && found=true
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
function Sync-SemanticRetrieval {
|
||||
param([Parameter(Mandatory=$true)][string]$RepositoryRoot,[Parameter(Mandatory=$true)][string]$HomePath,[ValidateSet('Codex','Claude','Both')][Parameter(Mandatory=$true)][string]$Client,[Parameter(Mandatory=$true)][bool]$Enabled,[switch]$DryRun,[switch]$Update,[switch]$Summary)
|
||||
$statePath = Join-Path $HomePath '.my-ai-configuration/semantic-retrieval.json'
|
||||
if (-not $Enabled -and -not (Test-Path -LiteralPath $statePath)) { return }
|
||||
$arguments = @((Join-Path $PSScriptRoot 'semantic-retrieval.py'), 'sync', '--root', $RepositoryRoot, '--home', $HomePath, '--client', $Client.ToLowerInvariant(), '--enabled', $Enabled.ToString().ToLowerInvariant())
|
||||
if ($DryRun) { $arguments += '--dry-run' }; if ($Update) { $arguments += '--update' }
|
||||
if ($Summary) { $arguments += '--summary' }
|
||||
& python @arguments
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Semantic retrieval reconciliation failed.' }
|
||||
}
|
||||
|
||||
function Test-SemanticRetrievalDevice {
|
||||
param([Parameter(Mandatory=$true)][string]$RepositoryRoot,[Parameter(Mandatory=$true)][string]$HomePath,[switch]$Summary)
|
||||
& python (Join-Path $PSScriptRoot 'semantic-retrieval.py') benchmark --root $RepositoryRoot --home $HomePath $(if ($Summary) { '--summary' }) | Write-Host
|
||||
if ($LASTEXITCODE -eq 0) { return $true }
|
||||
if ($LASTEXITCODE -eq 2) { return $false }
|
||||
throw 'Semantic retrieval benchmark failed.'
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
FILES = ('server.py', 'benchmark.py', 'requirements.txt')
|
||||
CUDA_INDEX = 'https://download.pytorch.org/whl/cu126'
|
||||
MODEL_PRELOAD_TIMEOUT = 900
|
||||
|
||||
|
||||
def digest(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def python_path(target):
|
||||
return target / ('Scripts/python.exe' if os.name == 'nt' else 'bin/python')
|
||||
|
||||
|
||||
def ensure_runtime(target, dry_run):
|
||||
if dry_run:
|
||||
return python_path(target / '.venv')
|
||||
venv = target / '.venv'
|
||||
if not venv.exists():
|
||||
subprocess.run([sys.executable, '-m', 'venv', str(venv)], check=True, timeout=180)
|
||||
python = python_path(venv)
|
||||
if not python.is_file():
|
||||
raise ValueError('Semantic retrieval virtual environment is incomplete.')
|
||||
arguments = [str(python), '-m', 'pip', 'install', '--disable-pip-version-check', '-r', str(target / 'requirements.txt')]
|
||||
if shutil.which('nvidia-smi'):
|
||||
try:
|
||||
subprocess.run([*arguments, '--extra-index-url', CUDA_INDEX], check=True, timeout=900)
|
||||
except subprocess.CalledProcessError:
|
||||
print('Semantic retrieval: CUDA runtime installation failed; falling back to CPU.', file=sys.stderr)
|
||||
subprocess.run(arguments, check=True, timeout=900)
|
||||
else:
|
||||
subprocess.run(arguments, check=True, timeout=900)
|
||||
return python
|
||||
|
||||
|
||||
def ensure_models(python, target):
|
||||
subprocess.run([str(python), str(target / 'server.py'), 'preload', '--model-cache', str(target / 'model-cache')],
|
||||
check=True, timeout=MODEL_PRELOAD_TIMEOUT)
|
||||
|
||||
|
||||
def load_state(path):
|
||||
if not path.exists():
|
||||
return {'version': 1, 'clients': [], 'files': {}}
|
||||
state = json.loads(path.read_text(encoding='utf-8'))
|
||||
if state.get('version') != 1 or not isinstance(state.get('clients'), list) or not isinstance(state.get('files'), dict):
|
||||
raise ValueError('Invalid semantic retrieval ownership state.')
|
||||
if any(client not in ('codex', 'claude') for client in state['clients']):
|
||||
raise ValueError('Invalid semantic retrieval client state.')
|
||||
if any(name not in FILES or not isinstance(value, str) or len(value) != 64 or any(character not in '0123456789abcdef' for character in value) for name, value in state['files'].items()):
|
||||
raise ValueError('Invalid semantic retrieval file state.')
|
||||
return state
|
||||
|
||||
|
||||
def save_state(path, state, dry_run):
|
||||
if not dry_run:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = None
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', dir=path.parent, delete=False) as stream:
|
||||
temporary = Path(stream.name)
|
||||
json.dump(state, stream, indent=2)
|
||||
stream.write('\n')
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
os.replace(temporary, path)
|
||||
finally:
|
||||
if temporary is not None:
|
||||
temporary.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def check_runtime(target, state):
|
||||
if target.is_symlink():
|
||||
raise ValueError('Semantic retrieval directory must not be a symbolic link.')
|
||||
if not target.exists():
|
||||
return
|
||||
if not target.is_dir():
|
||||
raise ValueError('Semantic retrieval target is not a directory.')
|
||||
for name, expected in state['files'].items():
|
||||
path = target / name
|
||||
if path.is_symlink() or not path.is_file() or digest(path) != expected:
|
||||
raise ValueError(f'Owned semantic retrieval file changed: {name}')
|
||||
allowed = set(state['files']) | {'.venv', 'model-cache', '__pycache__', 'data'}
|
||||
for path in target.iterdir():
|
||||
if path.is_symlink() or path.name not in allowed:
|
||||
raise ValueError(f'Foreign or linked semantic retrieval path: {path.name}')
|
||||
if path.name == 'data' and (not path.is_dir() or any(
|
||||
child.is_symlink() or not (
|
||||
child.is_file() and (child.name in ('daemon.key', 'daemon.starting') or re.fullmatch(
|
||||
r'[0-9a-f]{64}\.sqlite3(?:-(?:wal|shm|journal))?|daemon-[0-9a-f]{12}\.starting', child.name))
|
||||
or child.is_socket() and re.fullmatch(r'daemon-[0-9a-f]{16}\.sock', child.name))
|
||||
for child in path.iterdir())):
|
||||
raise ValueError('Foreign or linked semantic retrieval path: data')
|
||||
if path.name == '__pycache__' and (not path.is_dir() or any(
|
||||
child.is_symlink() or not child.is_file() or not re.fullmatch(
|
||||
r'(?:server|benchmark)\.[A-Za-z0-9_-]+(?:\.opt-\d+)?\.pyc', child.name)
|
||||
for child in path.iterdir())):
|
||||
raise ValueError('Foreign or linked semantic retrieval path: __pycache__')
|
||||
|
||||
|
||||
def sync(root, home, clients, enabled, dry_run, update, summary=False):
|
||||
base = home / '.my-ai-configuration'
|
||||
target = base / 'semantic-retrieval'
|
||||
state_path = base / 'semantic-retrieval.json'
|
||||
state = load_state(state_path)
|
||||
clients = list(dict.fromkeys(clients))
|
||||
if base.exists() and base.is_symlink():
|
||||
raise ValueError('Semantic retrieval state directory must not be a symbolic link.')
|
||||
if not enabled:
|
||||
owned = [client for client in state['clients'] if client in clients]
|
||||
if dry_run:
|
||||
if not summary:
|
||||
print('DRYRUN disable semantic retrieval: ' + (', '.join(owned) if owned else 'nothing owned'))
|
||||
return
|
||||
state['clients'] = [client for client in state['clients'] if client not in clients]
|
||||
if state['clients']:
|
||||
save_state(state_path, state, False)
|
||||
return
|
||||
if not state['files']:
|
||||
state_path.unlink(missing_ok=True)
|
||||
return
|
||||
check_runtime(target, state)
|
||||
if target.exists() and target.is_dir():
|
||||
shutil.rmtree(target)
|
||||
state_path.unlink(missing_ok=True)
|
||||
return
|
||||
|
||||
check_runtime(target, state)
|
||||
if target.exists() and not state['files']:
|
||||
raise ValueError('Semantic retrieval directory exists without setup ownership; refusing to overwrite it.')
|
||||
if dry_run:
|
||||
if not summary:
|
||||
print('DRYRUN enable semantic retrieval: Qwen3-Embedding-0.6B + Qwen3-Reranker-0.6B')
|
||||
return
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
source = root / 'shared' / 'retrieval'
|
||||
for name in FILES:
|
||||
shutil.copy2(source / name, target / name)
|
||||
state['files'][name] = digest(target / name)
|
||||
save_state(state_path, state, False)
|
||||
python = ensure_runtime(target, False)
|
||||
ensure_models(python, target)
|
||||
# Sandboxed clients may write only to data/; it cannot be created from inside the sandbox.
|
||||
(target / 'data').mkdir(exist_ok=True)
|
||||
state['clients'] = list(dict.fromkeys(state['clients']))
|
||||
save_state(state_path, state, False)
|
||||
for client in clients:
|
||||
if client not in state['clients']:
|
||||
state['clients'].append(client)
|
||||
save_state(state_path, state, False)
|
||||
save_state(state_path, state, False)
|
||||
|
||||
|
||||
def benchmark(root, home, dry_run, summary=False):
|
||||
base = home / '.my-ai-configuration'
|
||||
target = base / 'semantic-retrieval'
|
||||
state_path = base / 'semantic-retrieval.json'
|
||||
if dry_run:
|
||||
if not summary:
|
||||
print('DRYRUN benchmark semantic retrieval: Qwen3-Embedding-0.6B + Qwen3-Reranker-0.6B')
|
||||
return True
|
||||
state = load_state(state_path)
|
||||
source = root / 'shared' / 'retrieval'
|
||||
if state['files']:
|
||||
check_runtime(target, state)
|
||||
elif target.is_symlink():
|
||||
raise ValueError('Semantic retrieval directory must not be a symbolic link.')
|
||||
if target.exists() and not state['files']:
|
||||
if not all((target / name).is_file() and digest(target / name) == digest(source / name) for name in FILES):
|
||||
raise ValueError('Semantic retrieval directory exists without setup ownership; refusing to overwrite it.')
|
||||
state['files'] = {name: digest(target / name) for name in FILES}
|
||||
check_runtime(target, state)
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
for name in FILES:
|
||||
shutil.copy2(source / name, target / name)
|
||||
state['files'][name] = digest(target / name)
|
||||
python = ensure_runtime(target, False)
|
||||
result = subprocess.run([str(python), str(target / 'benchmark.py'), '--model-cache', str(target / 'model-cache')], check=True,
|
||||
stdout=subprocess.PIPE, text=True, timeout=300)
|
||||
outcome = json.loads(result.stdout)
|
||||
if not isinstance(outcome, dict) or not isinstance(outcome.get('recommended'), bool):
|
||||
raise ValueError('Semantic retrieval benchmark returned an invalid result.')
|
||||
if outcome['recommended'] or state['clients']:
|
||||
save_state(state_path, state, False)
|
||||
else:
|
||||
check_runtime(target, state)
|
||||
shutil.rmtree(target)
|
||||
state_path.unlink(missing_ok=True)
|
||||
if not summary:
|
||||
print('Semantic retrieval warm-model check: ' + ('passed' if outcome['recommended'] else 'failed') + f" (embedding {outcome['embeddingSeconds']}s, reranking {outcome['rerankingSeconds']}s; excludes model startup and indexing)")
|
||||
return outcome['recommended']
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('action', choices=('sync', 'benchmark'))
|
||||
parser.add_argument('--root', required=True, type=Path)
|
||||
parser.add_argument('--home', required=True, type=Path)
|
||||
parser.add_argument('--client', choices=('codex', 'claude', 'both'))
|
||||
parser.add_argument('--enabled', choices=('true', 'false'))
|
||||
parser.add_argument('--dry-run', action='store_true')
|
||||
parser.add_argument('--update', action='store_true')
|
||||
parser.add_argument('--summary', action='store_true')
|
||||
args = parser.parse_args()
|
||||
if args.action == 'benchmark':
|
||||
recommended = benchmark(args.root.resolve(), args.home.resolve(), args.dry_run, args.summary)
|
||||
raise SystemExit(0 if recommended else 2)
|
||||
if args.client is None or args.enabled is None:
|
||||
parser.error('sync requires --client and --enabled')
|
||||
clients = ('codex', 'claude') if args.client == 'both' else (args.client,)
|
||||
sync(args.root.resolve(), args.home.resolve(), clients, args.enabled == 'true', args.dry_run, args.update, args.summary)
|
||||
print('SEMANTIC RETRIEVAL: reconciliation complete' + (' (dry run)' if args.dry_run else ''))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except (OSError, ValueError, json.JSONDecodeError, subprocess.SubprocessError) as error:
|
||||
print(f'Semantic retrieval: {error}', file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sync_semantic_retrieval() {
|
||||
local root=$1 client=$2 home_path=$3 enabled=$4 dry_run=$5 update=$6 summary=${7:-false}
|
||||
[ "$enabled" = true ] || [ -f "$home_path/.my-ai-configuration/semantic-retrieval.json" ] || return 0
|
||||
local arguments=("$root/scripts/lib/semantic-retrieval.py" sync --root "$root" --home "$home_path" --client "$client" --enabled "$enabled")
|
||||
[ "$dry_run" != true ] || arguments+=(--dry-run)
|
||||
[ "$update" != true ] || arguments+=(--update)
|
||||
[ "$summary" != true ] || arguments+=(--summary)
|
||||
python3 "${arguments[@]}"
|
||||
}
|
||||
|
||||
test_semantic_retrieval_device() {
|
||||
local root=$1 home_path=$2 summary=${3:-false}
|
||||
local arguments=("$root/scripts/lib/semantic-retrieval.py" benchmark --root "$root" --home "$home_path")
|
||||
[ "$summary" != true ] || arguments+=(--summary)
|
||||
local status
|
||||
if python3 "${arguments[@]}" >&2; then return 0; else status=$?; fi
|
||||
[ "$status" -eq 2 ] && return 1
|
||||
return 2
|
||||
}
|
||||
Reference in new issue
Block a user