candidates and board ui agent issue
Some checks failed
CI / check (push) Failing after 4m58s

This commit is contained in:
2026-09-05 10:46:06 +05:30
parent e02a0c23d4
commit 6249e00a3a
78 changed files with 15071 additions and 1998 deletions

View File

@@ -187,3 +187,70 @@ export function toolsForContext(contextId, disabled = [], customSkills = []) {
*/
export const toolAllowed = (name, allowed = []) =>
allowed.some((tool) => tool.name === name);
/* ── Typed action intent ────────────────────────────────────────────────── */
/**
* How much has to be typed before a partial word counts as an intent.
*
* Three, and the number is the whole point of the rule. One or two characters
* cannot say what somebody meant — "wh" is the start of four unrelated
* questions — and offering anything on them is how the composer ended up
* interrupting every reader who had already decided what to ask. Three is the
* shortest prefix of a real verb, and it still matches nothing unless it is
* genuinely the beginning of an action this page can perform.
*/
const ACTION_INTENT_MIN = 3;
/**
* A phrase reduced to what it means, so matching is about intent not typing.
*
* Case, surrounding space and an article are not differences: "Create",
* "create" and "create a" are all the beginning of the same request. Kept local
* and deliberately tiny — it exists to compare two short phrases, and anything
* cleverer would start deciding what a reader meant.
*/
const canon = (value) => String(value || '')
.toLowerCase()
.trim()
.split(/\s+/)
.filter((w) => w && !/^(?:a|an|the)$/.test(w))
.join(' ');
/**
* The actions this page can perform that the typed text is starting to name.
*
* Derived, never listed. The phrases come from the skills themselves — a
* definition's `prompt:` is the sentence its author wrote for exactly this
* purpose — and the candidate set is whatever `skillsForContext` already
* resolved, which has the page filter and the agent's scoping applied to it.
* So a skill added tomorrow is offered here without this file changing, a skill
* switched off in Settings is not offered at all, and there is no second list
* of action names to keep in step with the first.
*
* Only skills that DECLARE an action are eligible. A reading skill has nothing
* to autocomplete towards: "which positions are in draft" is a question, and
* offering it while somebody types is the generic-catalogue behaviour this
* replaced.
*
* Matched on `canon`, so "Create" reaches "Create a position" — the article and
* the case are not differences — and "create position" reaches it too. A prefix
* rather than a substring: typing the middle of a phrase is not evidence of
* intent, and substring matching is what made every keystroke produce chips.
*/
export function actionSuggestions(typed, skills = []) {
const query = canon(typed);
if (query.length < ACTION_INTENT_MIN) return [];
const seen = new Set();
const out = [];
for (const skill of skills) {
if (!skill?.prompt || !skill.actions?.length) continue;
const phrase = canon(skill.prompt);
if (!phrase.startsWith(query)) continue;
if (seen.has(phrase)) continue;
seen.add(phrase);
out.push({ label: skill.prompt, prompt: skill.prompt });
}
return out;
}