more elaborate flow

This commit is contained in:
felix
2026-09-16 00:25:40 +02:00
parent 776b50c7d4
commit efa248cfd4
9 changed files with 467 additions and 83 deletions

View File

@@ -3,7 +3,6 @@
// never has to search the short ones.
import { fieldsOf, entityForClass } from '../runner/profile.js';
import { sessionQuery } from '../db.js';
const INLINE_VALUES_MAX = Number(process.env.INLINE_VALUES_MAX || 50);
const VALUES_TTL = Number(process.env.VALUES_TTL || 3600) * 1000;
@@ -11,26 +10,28 @@ const VALUES_TTL = Number(process.env.VALUES_TTL || 3600) * 1000;
// In-memory cache: profile+field → { values, at }. Refreshed lazily when stale.
const cache = new Map();
export async function codeListValues(profile) {
// Returns a map: "shapeUri|predicate|inverse" → [{ uri, label }]
// codeListValues(profile, queryFn) → map "shapeUri|predicate|inverse"
// → [{ uri, label }]. queryFn runs under the service scope (public graph), so
// code lists read the same regardless of the caller's rights.
export async function codeListValues(profile, queryFn) {
const out = {};
for (const shape of profile.shapes) {
for (const f of shape.fields) {
if (!f.class) continue;
const key = `${shape.uri}|${f.path}|${f.inverse ? 1 : 0}`;
out[key] = await loadCodeList(profile, f, key);
out[key] = await loadCodeList(f, key, queryFn);
}
}
return out;
}
async function loadCodeList(profile, f, key) {
async function loadCodeList(f, key, queryFn) {
if (!f.class) return [];
const hit = cache.get(key);
if (hit && Date.now() - hit.at < VALUES_TTL) return hit.values;
let values = [];
try {
values = await queryCodeList(f.class);
values = await queryCodeList(f.class, queryFn);
} catch (e) {
// the read failed; report nothing, the LLM will use rep:anyOf with words
values = [];
@@ -39,12 +40,12 @@ async function loadCodeList(profile, f, key) {
return values;
}
async function queryCodeList(type) {
async function queryCodeList(type, queryFn) {
const q = `SELECT ?uri ?label WHERE {
?uri a <${type}> .
OPTIONAL { ?uri <http://www.w3.org/2004/02/skos/core#prefLabel> ?label . }
} ORDER BY ?label LIMIT ${INLINE_VALUES_MAX + 1}`;
const r = await sessionQuery(q);
const r = await queryFn(q);
const bindings = r.results.bindings;
return bindings.slice(0, INLINE_VALUES_MAX).map(b => ({
uri: b.uri.value,