agnets done

This commit is contained in:
2026-08-28 11:02:02 +05:30
parent ab9adde6cd
commit eaf08e061d
58 changed files with 3506 additions and 4308 deletions

View File

@@ -1,4 +1,4 @@
import { canonicalPage } from '@/lib/skills/surfaces';
import { DOMAIN_SURFACES, canonicalPage } from '@/lib/skills/surfaces';
import { pageKeyForContext } from '@/lib/skills/registry';
import { getAgent } from './registry';
import { reasoningFor } from './vocabulary';
@@ -122,19 +122,33 @@ export function agentsForContext(agents = [], contextId) {
}
/**
* The general agent every page falls back to.
* Whether an agent is a *general* one: it covers every domain surface.
*
* Named once, here, because two different things need it and neither should
* carry its own copy: resolving a default, and deciding whether a page has an
* agent *of its own*.
* Derived from the definition rather than matched against an id. This used to
* be `FALLBACK_AGENT_ID = 'krow-workforce-agent'` — a literal agent key that
* two functions below branched on, which is precisely the thing agent specs
* being data is supposed to make impossible. With a key in the runtime,
* renaming the general agent silently demotes it, deleting it leaves two dead
* branches, and a workspace can never write a second general agent because
* only one id is privileged.
*
* Reading `pages` instead makes it a fact about the spec: an agent listing
* every surface that holds workforce records is an agent with no speciality,
* which is exactly what makes it the sensible fallback. A general agent may
* list *more* than the domain surfaces — the workforce agent also covers the
* agent workspace — so this is a subset test, never an equality one.
*/
export const FALLBACK_AGENT_ID = 'krow-workforce-agent';
export function isGeneralAgent(agent) {
if (!agent?.pages?.length) return false;
const covered = new Set(agent.pages);
return DOMAIN_SURFACES.every((id) => covered.has(id));
}
/**
* The agent written *for* this page, if there is one.
*
* The general agent is deliberately excluded. It covers every surface — which
* is what makes it a fallback — so counting it as a page's own agent would make
* General agents are deliberately excluded. One covers every surface — which is
* what makes it a fallback — so counting it as a page's own agent would make
* "does this page have a native agent?" true everywhere and the distinction
* meaningless.
*
@@ -142,20 +156,26 @@ export const FALLBACK_AGENT_ID = 'krow-workforce-agent';
* a broken one: see `resolveDefaultAgent`.
*/
export function nativeAgentForContext(agents = [], contextId) {
return agentsForContext(agents, contextId).find((a) => a.id !== FALLBACK_AGENT_ID) || null;
return agentsForContext(agents, contextId).find((a) => !isGeneralAgent(a)) || null;
}
/**
* The general agent, when it can answer here.
* The general agent, when one can answer here.
*
* Falls through to whichever published agent covers the page if the general one
* has been archived or does not list this surface — a page must never be left
* without an agent because of how the registry happens to be configured.
* `agentsForContext` has already narrowed to published agents covering this
* page and sorted them most-specific-first, so general agents sit at the end
* and the *last* of them is the broadest. Taking that one is identical to the
* old behaviour while exactly one general agent exists, and is a stated choice
* rather than an arbitrary one once a workspace has written a second.
*
* Falls through to whichever published agent covers the page when no general
* one does — a page must never be left without an agent because of how the
* registry happens to be configured.
*/
export function fallbackAgentForContext(agents = [], contextId) {
const general = getAgent(agents, FALLBACK_AGENT_ID);
if (general && general.status === 'published' && agentCovers(general, contextId)) return general;
return agentsForContext(agents, contextId)[0] || null;
const covering = agentsForContext(agents, contextId);
const general = covering.filter(isGeneralAgent);
return general[general.length - 1] || covering[0] || null;
}
/**