caveat-cli 0.19.8 → 0.19.9

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/dist/index.js CHANGED
@@ -33210,6 +33210,7 @@ var API_URL = "https://api.typesafe.ai/v1/systemone";
33210
33210
  var STRUGGLE_THRESHOLD = 0.85;
33211
33211
  var MATCH_THRESHOLD = 0.8;
33212
33212
  var MAX_TERMS = 48;
33213
+ var MAX_SEARCH_TERMS = 3;
33213
33214
  var MAX_CANDIDATES = 20;
33214
33215
  async function callJev(key, state, questions, fetcher = fetch) {
33215
33216
  const response = await fetcher(API_URL, {
@@ -33232,9 +33233,16 @@ function noul(answer) {
33232
33233
  }
33233
33234
  return answer.noul;
33234
33235
  }
33235
- function choice(answer, allowed) {
33236
- if (answer?.type !== "choice" || !allowed.has(answer.choice)) throw new Error("jev_choice_invalid");
33237
- return answer.choice;
33236
+ function searchTermChoices(answer, terms) {
33237
+ if (answer?.type !== "choice" || !isRecord(answer.probabilities)) throw new Error("jev_choice_invalid");
33238
+ const keys = terms.map((_, index) => `term_${index}`);
33239
+ const allowed = /* @__PURE__ */ new Set([...keys, "none"]);
33240
+ if (!allowed.has(answer.choice) || Object.keys(answer.probabilities).length !== allowed.size || Object.entries(answer.probabilities).some(([key, probability]) => !allowed.has(key) || typeof probability !== "number" || !Number.isFinite(probability) || probability < 0 || probability > 1)) {
33241
+ throw new Error("jev_choice_invalid");
33242
+ }
33243
+ if (answer.choice === "none") return [];
33244
+ const noneProbability = answer.probabilities.none;
33245
+ return keys.map((key, index) => ({ index, probability: answer.probabilities[key] })).filter(({ probability }) => probability > noneProbability).sort((a, b) => b.probability - a.probability || a.index - b.index).slice(0, MAX_SEARCH_TERMS).map(({ index }) => terms[index]);
33238
33246
  }
33239
33247
  function candidateTerms(turns) {
33240
33248
  const found = /* @__PURE__ */ new Map();
@@ -33262,14 +33270,13 @@ async function judgeStruggle(key, turns, ask = callJev) {
33262
33270
  };
33263
33271
  if (terms.length > 0) questions.search_term = {
33264
33272
  type: "choice",
33265
- instructions: "If the agent is struggling, which exact term from these options would best retrieve a useful Caveat knowledge entry about the concrete unresolved problem? Select none when no option identifies it.",
33273
+ instructions: "If the agent is struggling, which exact term from these options would best retrieve a useful Caveat knowledge entry about the concrete unresolved problem? Select none when no option identifies it. The search will use up to three of your highest-ranked terms together as an AND query.",
33266
33274
  criteria: { ...options, none: "No listed term would retrieve useful knowledge about this problem." }
33267
33275
  };
33268
33276
  const response = await ask(key, { turns }, questions);
33269
33277
  const struggling = noul(response.answers.repeated_problem) >= STRUGGLE_THRESHOLD && noul(response.answers.clearly_stuck) >= STRUGGLE_THRESHOLD;
33270
- if (!struggling || terms.length === 0) return { struggling, term: null };
33271
- const selected = choice(response.answers.search_term, /* @__PURE__ */ new Set([...Object.keys(options), "none"]));
33272
- return { struggling, term: selected === "none" ? null : terms[Number(selected.slice(5))] ?? null };
33278
+ if (!struggling || terms.length === 0) return { struggling, terms: [] };
33279
+ return { struggling, terms: searchTermChoices(response.answers.search_term, terms) };
33273
33280
  }
33274
33281
  async function rankKnowledge(key, turns, candidates, ask = callJev) {
33275
33282
  if (candidates.length === 0) return null;
@@ -33373,21 +33380,22 @@ async function runJevStruggle(ctx, host, payload, deps = {}) {
33373
33380
  return null;
33374
33381
  }
33375
33382
  let candidates = [];
33376
- if (judgment.term) {
33383
+ const query = judgment.terms.join(" ");
33384
+ if (query) {
33377
33385
  if (!existsSync14(ctx.paths.dbPath)) throw new Error("jev_knowledge_index_missing");
33378
33386
  const db = openDb({ path: ctx.paths.dbPath });
33379
33387
  try {
33380
33388
  const taskText = context.turns.map((turn) => `${turn.user}
33381
33389
  ${turn.assistant}
33382
33390
  ${turn.thinking}`).join("\n");
33383
- candidates = search(db, { query: judgment.term, limit: MAX_CANDIDATES }).filter((hit) => environmentAppliesToTask(hit.environment, taskText, fingerprint().os)).map((hit) => ({ hit, entry: get(db, hit.id, hit.source) })).filter((item) => item.entry !== null).filter((item) => Boolean(item.entry.sections.Resolution));
33391
+ candidates = search(db, { query, limit: MAX_CANDIDATES }).filter((hit) => environmentAppliesToTask(hit.environment, taskText, fingerprint().os)).map((hit) => ({ hit, entry: get(db, hit.id, hit.source) })).filter((item) => item.entry !== null).filter((item) => Boolean(item.entry.sections.Resolution));
33384
33392
  } finally {
33385
33393
  db.close();
33386
33394
  }
33387
33395
  }
33388
33396
  const selected = await rankKnowledge(key, context.turns, candidates, ask);
33389
33397
  const id = selected ? `${selected.hit.source}/${selected.hit.id}` : null;
33390
- const term = judgment.term ?? "_none";
33398
+ const term = query || "_none";
33391
33399
  if (id && (state.deliveredIds.includes(id) || wasHitDelivered(ctx.caveatHome, sessionId, id)) || !id && state.notifiedTerms.includes(term)) {
33392
33400
  saveState(ctx.caveatHome, sessionId, state);
33393
33401
  return null;