从真实目录生成任务范围内的菜单
策略的具体实现如下。
ts
export function defineAgentCatalog<
App,
Id extends string,
Goal extends CatalogGoal<Id>,
Scope extends CatalogScope,
>(ports: AgentCatalogPorts<App, Id, Goal, Scope>) {
const ids = ports.goalIds.bind(ports),
goals = ports.goals.bind(ports),
scopes = ports.scopes.bind(ports),
task = ports.currentTask.bind(ports);
const tools = {
values: ports.tools.values.bind(ports.tools),
has: ports.tools.has.bind(ports.tools),
supports: ports.tools.supportsGoal.bind(ports.tools),
describe: ports.tools.describe.bind(ports.tools),
};
const restrict = ports.restrictToTask !== false;
const boolean = (value: unknown) =>
booleanResult(
value,
'Catalog predicates must be synchronous',
'Catalog predicates must return boolean',
);
/** Whether one goal is active and its demand metadata currently participates. */
const goalAvailable = (goal: Goal, app: App): boolean => {
const tool = goal as Goal & Partial<ModelTool<unknown, unknown, App>>;
if (!toolActive(tool.active, app)) return false;
const metadata = tool.asIntent;
if (metadata === undefined || metadata === true || typeof metadata === 'string') return true;
if (typeof metadata === 'function') return toolActive(metadata, app);
return toolActive(metadata.when, app);
};
const goalIds = (app: App) => ids(app).filter((id) => boolean(tools.supports(id, app)));
const goalDelegates = (app?: App) =>
new Map(
goals().map((goal) => {
const metadata = (
goal as Goal & Partial<import('../../structs/capabilities/model.js').ModelTool>
).asIntent;
const explicit = typeof metadata === 'object' ? metadata.delegates : undefined;
return [
goal.id,
explicit
? [...explicit]
: [
...new Set([
...goal.delegates,
...[...tools.values()]
.filter(
(tool) =>
tool.lifecycle?.id &&
(app === undefined || toolActive(tool.active, app)) &&
(tool.goalIds === 'all' || tool.goalIds.includes(goal.id)),
)
.map((tool) => tool.lifecycle!.id!),
]),
],
] as const;
}),
);
const goalCatalog = (app: App) => {
const selected = goalIds(app),
described = tools.describe('model', app),
delegates = goalDelegates(app);
return goals(selected)
.filter((goal) => goalAvailable(goal, app))
.map((goal) => {
const {
inputSchema: _schema,
resolve: _resolve,
active: _active,
asIntent: _asIntent,
...metadata
} = goal as Goal & Partial<ModelTool<unknown, unknown, App>>;
const demandDescription =
typeof _asIntent === 'string'
? _asIntent
: typeof _asIntent === 'object' && _asIntent !== null
? _asIntent.description
: undefined;
return {
...metadata,
...(demandDescription ? { description: demandDescription } : {}),
delegates: delegates.get(goal.id) ?? [...goal.delegates],
scopeIds: scopes([goal.id]).map((scope) => scope.id),
toolIds: described
.filter((tool) => tool.goalIds.includes(goal.id))
.map((tool) => tool.id),
};
});
};
const scopeCatalog = (app: App) =>
scopes(goalCatalog(app).map((goal) => goal.id)).map((scope) => ({
...scope,
toolIds: scope.toolIds.filter(tools.has),
}));
return Object.freeze({
goalIds,
goalDelegates,
goalCatalog,
scopeCatalog,
modelCatalog(app: App) {
const accepted = restrict ? task(app) : undefined,
selected = goalIds(app).filter((id) => !accepted || id === accepted.goalId),
available = goalCatalog(app).filter((intent) => selected.includes(intent.id));
return {
availableGoalIds: available.map((intent) => intent.id),
availableGoals: available.map((intent) =>
accepted ? { ...intent, scopeIds: accepted.scopeId ? [accepted.scopeId] : [] } : intent,
),
availableScopes: scopeCatalog(app).filter(
(scope) => !accepted || scope.id === accepted.scopeId,
),
availableTools: tools
.describe('model', app)
.filter((tool) => !accepted || tool.goalIds.includes(accepted.goalId)),
};
},
});
}