feat: unify installation model catalog

This commit is contained in:
Codex
2026-09-02 18:45:33 +02:00
parent ae053961a3
commit 7b7927bfe5
169 changed files with 3696 additions and 4572 deletions
+148 -47
View File
@@ -317,12 +317,14 @@ task13_compose_files() {
-f "$TASK13_ROOT/deploy/compose.server.yaml"
-f "$TASK13_ROOT/deploy/compose.session-server.yaml.example"
-f "$TASK13_OVERRIDE"
-f "${TASK13_INSTALLATION%/*}/generated/compose.models.yaml"
-f "$TASK13_ROOT/deploy/compose.auth-runtime-projection.yaml"
)
else
TASK13_COMPOSE+=(
-f "$TASK13_ROOT/deploy/compose.local.yaml"
-f "$TASK13_OVERRIDE"
-f "${TASK13_INSTALLATION%/*}/generated/compose.models.yaml"
)
fi
if [[ "${TASK13_PROFILE:-local}" == local && -f "$TASK13_CURRENT_IMAGE_OVERRIDE" ]]; then
@@ -414,6 +416,100 @@ EOF
chmod 0600 "$TASK13_SESSION_CA"
}
# Test-only materialization of the same deterministic boundary adapters covered by the Go
# modelprojection tests. Production lifecycle commands always generate these files themselves.
task13_write_model_projection_fixture() {
python3 - "$TASK13_INSTALLATION" "$TASK13_LLM_CONTAINER" <<'PY'
import hashlib
import json
from pathlib import Path
import sys
installation = Path(sys.argv[1])
provider_host = sys.argv[2]
generated = installation.parent / "generated"
(generated / "pi").mkdir(parents=True, exist_ok=True)
catalog = {
"schemaVersion": 1,
"defaultSession": "local-qwen/task13-smoke",
"embedding": {"id": "ollama/qwen3-embedding:0.6b", "dimensions": 1024},
"models": [{
"id": "local-qwen/task13-smoke",
"provider": "local-qwen",
"model": "task13-smoke",
"label": "Task 13 deterministic smoke",
"upstreamModel": "task13-smoke",
"endpoint": {"baseUrl": f"http://{provider_host}:9000/v1"},
"authentication": {"mode": "none"},
"sessionAdapter": {"mode": "openai_compatible"},
"session": {
"reasoning": False,
"input": ["text"],
"cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0},
"contextWindow": 4096,
"maxTokens": 64,
},
}],
}
models = {
"providers": {"local-qwen": {
"baseUrl": f"http://{provider_host}:9000/v1",
"api": "openai-completions",
"apiKey": "local",
"models": [{
"id": "task13-smoke", "name": "Task 13 deterministic smoke",
"reasoning": False, "input": ["text"],
"cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0},
"contextWindow": 4096, "maxTokens": 64,
}],
}},
}
settings = {"defaultProjectTrust": "always", "enabledModels": ["local-qwen/task13-smoke"]}
serialized = []
for path, value in (
(generated / "catalog.json", catalog),
(generated / "pi/models.json", models),
(generated / "pi/settings.json", settings),
):
raw = json.dumps(value, indent=2, sort_keys=True) + "\n"
path.write_text(raw)
serialized.append(raw.encode())
revision = "sha256:" + hashlib.sha256(b"".join(serialized)).hexdigest()
quote = json.dumps
(generated / "compose.models.yaml").write_text(f"""services:
core:
environment:
THT_MODEL_CATALOG_FILE: /run/thothii-model-catalog/catalog.json
THT_MODEL_CATALOG_REVISION: {quote(revision)}
THT_DEFAULT_SESSION_MODEL: local-qwen/task13-smoke
THT_INTERNAL_EMBEDDING_ID: ollama/qwen3-embedding:0.6b
THT_INTERNAL_EMBEDDING_MODEL: qwen3-embedding:0.6b
THT_INTERNAL_EMBEDDING_DIMENSIONS: '1024'
volumes:
- type: bind
source: {quote(str(generated / 'catalog.json'))}
target: /run/thothii-model-catalog/catalog.json
read_only: true
- type: bind
source: {quote(str(generated / 'pi/models.json'))}
target: /home/thoth/.pi/agent/models.json
read_only: true
- type: bind
source: {quote(str(generated / 'pi/settings.json'))}
target: /home/thoth/.pi/agent/settings.json
read_only: true
workspace-maintenance:
environment:
THT_INTERNAL_EMBEDDING_ID: ollama/qwen3-embedding:0.6b
THT_INTERNAL_EMBEDDING_MODEL: qwen3-embedding:0.6b
THT_INTERNAL_EMBEDDING_DIMENSIONS: '1024'
embedding-model-init:
environment:
OLLAMA_MODEL: qwen3-embedding:0.6b
""")
PY
}
task13_write_fixture_files() {
printf '{}\n' >"$TASK13_PI_AUTH"
printf 'THT_MODEL_API_KEY=%s\n' "$TASK13_SECRET_VALUE" >"$TASK13_SECRETS"
@@ -425,41 +521,6 @@ task13_write_fixture_files() {
chmod 0700 "$TASK13_AUTH_ROOT"
chmod 0600 "$TASK13_SECRETS" "$TASK13_SESSION_RUNTIME_PASSWORD" "$TASK13_AUTH_PASSWORD_FILE"
cat >"$TASK13_PI_MODELS" <<EOF
{
"providers": {
"local-qwen": {
"baseUrl": "http://$TASK13_LLM_CONTAINER:9000/v1",
"api": "openai-completions",
"apiKey": "task13-local-provider",
"models": [
{
"id": "task13-smoke",
"name": "Task 13 deterministic smoke",
"reasoning": false,
"input": ["text"],
"cost": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0
},
"contextWindow": 4096,
"maxTokens": 64
}
]
}
}
}
EOF
cat >"$TASK13_PI_SETTINGS" <<'EOF'
{
"defaultProjectTrust": "always",
"enabledModels": ["local-qwen/task13-smoke"]
}
EOF
chmod 0644 "$TASK13_PI_MODELS" "$TASK13_PI_SETTINGS"
cat >"$TASK13_LLM_SERVER" <<'EOF'
import http from "node:http";
@@ -517,8 +578,6 @@ services:
labels:
io.thothii.task13.run: "$TASK13_RUN_ID"
environment:
PI_PROVIDER: local-qwen
PI_MODEL: task13-smoke
PI_THINKING: low
THT_WORKSPACE_INSTALLATION_ID: task13-smoke
THT_WORKSPACE_REGISTRY_ROOT: /data/workspace-registry
@@ -605,15 +664,40 @@ EOF
chmod 0600 "$TASK13_OVERRIDE"
cat >"$TASK13_INSTALLATION" <<EOF
schemaVersion: 2
profile: local
projectDirectory: "$TASK13_ROOT"
envFile: "$TASK13_ENV_FILE"
modelCatalog:
defaults:
session: local-qwen/task13-smoke
embedding:
id: ollama/qwen3-embedding:0.6b
dimensions: 1024
providers:
local-qwen:
endpoint:
baseUrl: http://$TASK13_LLM_CONTAINER:9000/v1
authentication:
mode: none
session:
mode: openai_compatible
models:
task13-smoke:
label: Task 13 deterministic smoke
session:
reasoning: false
input: [text]
cost: {input: 0, output: 0, cacheRead: 0, cacheWrite: 0}
contextWindow: 4096
maxTokens: 64
authentication:
configDirectory: "$TASK13_AUTH_ROOT"
overrides:
- "$TASK13_OVERRIDE"
EOF
chmod 0600 "$TASK13_INSTALLATION"
task13_write_model_projection_fixture
}
task13_write_server_fixture_files() {
@@ -805,9 +889,33 @@ EOF
chmod 0600 "$TASK13_ENV_FILE"
cat >"$TASK13_INSTALLATION" <<EOF
schemaVersion: 2
profile: server
projectDirectory: "$TASK13_ROOT"
envFile: "$TASK13_ENV_FILE"
modelCatalog:
defaults:
session: local-qwen/task13-smoke
embedding:
id: ollama/qwen3-embedding:0.6b
dimensions: 1024
providers:
local-qwen:
endpoint:
baseUrl: http://$TASK13_LLM_CONTAINER:9000/v1
authentication:
mode: none
session:
mode: openai_compatible
models:
task13-smoke:
label: Task 13 deterministic smoke
session:
reasoning: false
input: [text]
cost: {input: 0, output: 0, cacheRead: 0, cacheWrite: 0}
contextWindow: 4096
maxTokens: 64
authentication:
configDirectory: "$TASK13_AUTH_ROOT"
runtimeProjection:
@@ -819,6 +927,7 @@ overrides:
- "$TASK13_OVERRIDE"
EOF
chmod 0600 "$TASK13_INSTALLATION"
task13_write_model_projection_fixture
}
task13_workspace_metadata() {
@@ -1058,23 +1167,17 @@ task13_prepare_local_pi_runtime() {
--user 0:0 \
--entrypoint sh \
--volume "$TASK13_PI_AUTH:/source/auth.json:ro" \
--volume "$TASK13_PI_MODELS:/source/models.json:ro" \
--volume "$TASK13_PI_SETTINGS:/source/settings.json:ro" \
--volume "$TASK13_PI_RUNTIME_VOLUME:/target" \
"$TASK13_CORE_IMAGE" -ceu '
test -f /source/auth.json && test ! -L /source/auth.json
test -f /source/models.json && test ! -L /source/models.json
test -f /source/settings.json && test ! -L /source/settings.json
test -d /target/agent && test ! -L /target/agent
test -z "$(find /target -mindepth 1 -maxdepth 1 ! -name agent -print -quit)"
test -z "$(find /target/agent -mindepth 1 -maxdepth 1 -print -quit)"
cp /source/auth.json /source/models.json /source/settings.json /target/agent/
cp /source/auth.json /target/agent/
chown -R 10001:10001 /target
chmod 0700 /target /target/agent
chmod 0600 /target/agent/auth.json /target/agent/models.json /target/agent/settings.json
chmod 0600 /target/agent/auth.json
test "$(stat -c "%u:%g:%a" /target/agent/auth.json)" = 10001:10001:600
test "$(stat -c "%u:%g:%a" /target/agent/models.json)" = 10001:10001:600
test "$(stat -c "%u:%g:%a" /target/agent/settings.json)" = 10001:10001:600
'
}
@@ -2918,8 +3021,6 @@ task13_initialize() {
TASK13_AUTH_PASSWORD="task13-auth-$TASK13_RUN_ID"
TASK13_OIDC_CLIENT_SECRET="task13-oidc-client-$TASK13_RUN_ID"
TASK13_AUTHENTIK_API_TOKEN="task13-authentik-token-$TASK13_RUN_ID"
TASK13_PI_MODELS="$TASK13_TMP/models.json"
TASK13_PI_SETTINGS="$TASK13_TMP/pi-settings.json"
TASK13_LLM_SERVER="$TASK13_TMP/fake-llm.mjs"
TASK13_OIDC_SERVER="$TASK13_TMP/fake-oidc.mjs"
TASK13_OIDC_CERT="$TASK13_TMP/fake-oidc-cert.pem"