caveat-cli 0.19.7 → 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
@@ -26,7 +26,7 @@ import {
26
26
  defaultSelfIdentityTokens,
27
27
  ensureUserConfig,
28
28
  environmentAppliesToTask,
29
- extractPromptCandidates,
29
+ extractSearchWordCandidates,
30
30
  findCaveatHome,
31
31
  findCaveatsForHook,
32
32
  findCaveatsForHookSegments,
@@ -74,7 +74,7 @@ import {
74
74
  userPromptSubmitReminderText,
75
75
  writeDigestMarker,
76
76
  writeUserConfigPatch
77
- } from "./chunk-EMGYSGFX.js";
77
+ } from "./chunk-ITQLGM4K.js";
78
78
 
79
79
  // ../../node_modules/.pnpm/ajv@8.18.0/node_modules/ajv/dist/compile/codegen/code.js
80
80
  var require_code = __commonJS({
@@ -8390,7 +8390,7 @@ function runStats(ctx) {
8390
8390
 
8391
8391
  // src/commands/serve.ts
8392
8392
  async function runServe(opts) {
8393
- const { startServer } = await import("./server-RSDQNLWE.js");
8393
+ const { startServer } = await import("./server-H4BWLLZ2.js");
8394
8394
  const { port, host } = startServer({ port: opts.port });
8395
8395
  process.stdout.write(`[caveat] web portal: http://${host}:${port}/
8396
8396
  `);
@@ -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,33 +33233,33 @@ 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
- const seen = /* @__PURE__ */ new Set();
33241
- const terms = [];
33242
- const groups = [...turns].reverse().map((turn) => [turn.user, turn.thinking, turn.assistant].flatMap((part) => extractPromptCandidates(
33243
- part.replace(/(?<=[A-Za-z0-9])(?=[\u3040-\u30ff\u3400-\u9fff])|(?<=[\u3040-\u30ff\u3400-\u9fff])(?=[A-Za-z0-9])/gu, " ")
33244
- )));
33245
- const add = (term) => {
33246
- const key = term.toLocaleLowerCase();
33247
- if (seen.has(key) || terms.length >= MAX_TERMS) return;
33248
- seen.add(key);
33249
- terms.push(term);
33250
- };
33251
- for (const group of groups) {
33252
- let added = 0;
33253
- for (const term of group) {
33254
- const before = terms.length;
33255
- add(term);
33256
- if (terms.length > before) added++;
33257
- if (added === 12) break;
33258
- }
33259
- }
33260
- for (const group of groups) for (const term of group) add(term);
33261
- return terms;
33248
+ const found = /* @__PURE__ */ new Map();
33249
+ let position = 0;
33250
+ for (let turnIndex = 0; turnIndex < turns.length; turnIndex++) {
33251
+ const turn = turns[turnIndex];
33252
+ for (const part of [turn.user, turn.thinking, turn.assistant]) {
33253
+ for (const term of extractSearchWordCandidates(part)) {
33254
+ const key = term.toLocaleLowerCase();
33255
+ const item = found.get(key) ?? { term, turns: /* @__PURE__ */ new Set(), last: 0 };
33256
+ item.turns.add(turnIndex);
33257
+ item.last = position++;
33258
+ found.set(key, item);
33259
+ }
33260
+ }
33261
+ }
33262
+ return [...found.values()].sort((a, b) => b.turns.size - a.turns.size || b.last - a.last).slice(0, MAX_TERMS).map((item) => item.term);
33262
33263
  }
33263
33264
  async function judgeStruggle(key, turns, ask = callJev) {
33264
33265
  const terms = candidateTerms(turns);
@@ -33269,14 +33270,13 @@ async function judgeStruggle(key, turns, ask = callJev) {
33269
33270
  };
33270
33271
  if (terms.length > 0) questions.search_term = {
33271
33272
  type: "choice",
33272
- 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.",
33273
33274
  criteria: { ...options, none: "No listed term would retrieve useful knowledge about this problem." }
33274
33275
  };
33275
33276
  const response = await ask(key, { turns }, questions);
33276
33277
  const struggling = noul(response.answers.repeated_problem) >= STRUGGLE_THRESHOLD && noul(response.answers.clearly_stuck) >= STRUGGLE_THRESHOLD;
33277
- if (!struggling || terms.length === 0) return { struggling, term: null };
33278
- const selected = choice(response.answers.search_term, /* @__PURE__ */ new Set([...Object.keys(options), "none"]));
33279
- 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) };
33280
33280
  }
33281
33281
  async function rankKnowledge(key, turns, candidates, ask = callJev) {
33282
33282
  if (candidates.length === 0) return null;
@@ -33380,21 +33380,22 @@ async function runJevStruggle(ctx, host, payload, deps = {}) {
33380
33380
  return null;
33381
33381
  }
33382
33382
  let candidates = [];
33383
- if (judgment.term) {
33383
+ const query = judgment.terms.join(" ");
33384
+ if (query) {
33384
33385
  if (!existsSync14(ctx.paths.dbPath)) throw new Error("jev_knowledge_index_missing");
33385
33386
  const db = openDb({ path: ctx.paths.dbPath });
33386
33387
  try {
33387
33388
  const taskText = context.turns.map((turn) => `${turn.user}
33388
33389
  ${turn.assistant}
33389
33390
  ${turn.thinking}`).join("\n");
33390
- 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));
33391
33392
  } finally {
33392
33393
  db.close();
33393
33394
  }
33394
33395
  }
33395
33396
  const selected = await rankKnowledge(key, context.turns, candidates, ask);
33396
33397
  const id = selected ? `${selected.hit.source}/${selected.hit.id}` : null;
33397
- const term = judgment.term ?? "_none";
33398
+ const term = query || "_none";
33398
33399
  if (id && (state.deliveredIds.includes(id) || wasHitDelivered(ctx.caveatHome, sessionId, id)) || !id && state.notifiedTerms.includes(term)) {
33399
33400
  saveState(ctx.caveatHome, sessionId, state);
33400
33401
  return null;