fix(plugins): expose enabled skills for agent assignment
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# Task: Diagnose and fix Web Search tool routing from current main
|
||||
|
||||
## Identity
|
||||
|
||||
- Task ID: 20260901-web-search-tool-routing-fix-6f9d3b82
|
||||
- Mode: Feature
|
||||
- Branch: codex/20260901-web-search-tool-routing-fix-6f9d3b82-web-search-tool-routing-fix
|
||||
- Worktree: D:\Datas\OthersProjects\makelore-web-search-tool-routing-fix-6f9d3b82
|
||||
- Base commit: 08099ea1c2ea24efc10c20f878fc25a557ea9d90
|
||||
- Owner: codex-root
|
||||
- Status: Ready for Integration
|
||||
|
||||
## Scope
|
||||
|
||||
- Reproduce the reported installed-client behavior where an explicit request to use
|
||||
Web Search invokes `agent_browser` instead of `makelore_web_search`.
|
||||
- Trace the exact current package version, project Plugin selection, Agent Skill
|
||||
assignment, backend admission, effective frozen worker snapshot, and Pi CLI tool
|
||||
catalog without changing server policy or production data.
|
||||
- If a client defect is confirmed, add a regression at the narrow owning seam,
|
||||
implement the smallest fix, and verify the affected packaged/runtime path.
|
||||
|
||||
## Intent And Constraints
|
||||
|
||||
- Concurrent Task Gate: Passed in the isolated worktree from exact local
|
||||
`main` base `08099ea1c2ea24efc10c20f878fc25a557ea9d90`. The two unrelated
|
||||
untracked packaging records in the user root remain untouched.
|
||||
- Planning Gate: Passed after loading the project memory entry points, current
|
||||
architecture/data-flow/domain rules, ADR-006, evidence/commitments, the prior
|
||||
Web Search coordinator scope, and the two local 1.2.2/1.2.3 package records.
|
||||
- Confirmed product contract: official Web Search is bundled but optional; Account
|
||||
acquisition, project enablement, Agent assignment, current Admission, and the
|
||||
frozen parent worker snapshot are separate gates. Child workers receive no hosted
|
||||
tool.
|
||||
- Diagnosis must begin with a deterministic loop that observes the actual worker
|
||||
tool catalog. A prompt-only change is not acceptable unless the tool is proven
|
||||
present and the routing failure remains.
|
||||
- Preserve the current project, conversations, user data, credentials, unrelated
|
||||
task records, and production server state. No push, deploy, publication, paid
|
||||
Provider call, or destructive cleanup is in scope.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Confirmed the installed client is MakeLore 1.2.3 and the affected project has
|
||||
`makelore.web-search` enabled, but Agent `cc` is assigned only `agent-browser`.
|
||||
The latest persisted Pi session consequently exposes only `agent_browser`; this
|
||||
is not a model-choice conflict between two available tools.
|
||||
- Reproduced the client bootstrap defect at the Product Host seam: the unscoped
|
||||
Agent assignment catalog called the effective resolver with an empty assignment,
|
||||
then treated `effectiveSkillIds=[]` as the plugin availability set. An enabled
|
||||
Web Search Skill therefore disappeared until it had already been assigned.
|
||||
- Changed the unscoped catalog to use project-enabled plugin IDs directly and to
|
||||
avoid runtime/admission resolution. Agent-scoped projections still use the
|
||||
resolver-approved effective subset, so the fix does not materialize Web Search
|
||||
into a worker before explicit Agent assignment.
|
||||
- Added a regression proving an enabled/unassigned Web Search Skill is available
|
||||
in the assignment catalog, while the same Skill remains unavailable in Agent
|
||||
`builder`'s scoped projection until assigned.
|
||||
- Applied the requested operational correction to the affected project only:
|
||||
Agent `cc` now has `agent-browser` and `makelore-web-search`; the existing
|
||||
`makelore.web-search` project enablement remains unchanged.
|
||||
|
||||
## Verification
|
||||
|
||||
- TDD RED: `pnpm exec vitest run tests/unit/coding-product-services.test.ts` =
|
||||
1 failed / 10 passed; the enabled Web Search Skill was absent.
|
||||
- Focused GREEN: Product Host, effective resolver, capability registry, Pi resource
|
||||
loader, and composition = 5 files / 45 tests passed.
|
||||
- Full client suite on the final implementation = 215 files / 1785 passed / 2
|
||||
skipped, plus pressure 1/1 passed.
|
||||
- `pnpm run typecheck` passed. Scoped ESLint passed with zero findings.
|
||||
- The affected project JSON parses successfully and reports Agent `cc` Skills
|
||||
`agent-browser,makelore-web-search` with Web Search project enablement `true`.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- The currently running 1.2.3 process does not contain the assignment-catalog UI
|
||||
fix. The affected Agent assignment is already corrected on disk; start a new
|
||||
conversation so a new frozen parent worker reads it and includes
|
||||
`makelore_web_search`. Existing workers intentionally remain frozen.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- None recorded.
|
||||
@@ -674,7 +674,7 @@ export function createCodingProductHost(options: CodingProductHostOptions): Codi
|
||||
async listSkills(agentId) {
|
||||
const project = await activeProject();
|
||||
const assignedSkillIds = await selectedSkillIds(project.path, agentId);
|
||||
const effective = options.effectiveResolver
|
||||
const effective = agentId && options.effectiveResolver
|
||||
? await options.effectiveResolver.resolve({
|
||||
projectId: project.id,
|
||||
projectPath: project.path,
|
||||
@@ -687,11 +687,17 @@ export function createCodingProductHost(options: CodingProductHostOptions): Codi
|
||||
// still supplies the availability set; only the worker opener receives
|
||||
// the effective subset.
|
||||
const skillIds = assignedSkillIds;
|
||||
const enabledPluginIds = effective
|
||||
? effective.effectiveSkillIds
|
||||
: options.getEnabledPluginIds
|
||||
? await options.getEnabledPluginIds(project.path)
|
||||
: [];
|
||||
// The unscoped list is the Agent assignment catalog. It must expose
|
||||
// every project-enabled plugin Skill before that Skill has been assigned;
|
||||
// the resolver's effective subset is only authoritative once an Agent is
|
||||
// selected (and for worker-facing projections).
|
||||
const enabledPluginIds = !agentId && options.getEnabledPluginIds
|
||||
? await options.getEnabledPluginIds(project.path)
|
||||
: effective
|
||||
? effective.effectiveSkillIds
|
||||
: options.getEnabledPluginIds
|
||||
? await options.getEnabledPluginIds(project.path)
|
||||
: [];
|
||||
return await options.productTools.listSkills(
|
||||
skillIds,
|
||||
enabledPluginIds,
|
||||
|
||||
@@ -218,6 +218,56 @@ describe('PI-105 product Host composition', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('offers an enabled Web Search Skill before its first Agent assignment', async () => {
|
||||
const root = await configuredProject(['agent-browser']);
|
||||
const tools = new PiProductTools({
|
||||
browser: {} as AgentBrowserModule,
|
||||
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
|
||||
bundledSkillsDir: path.resolve('resources/coding-skills'),
|
||||
pluginSkillSources: [{
|
||||
id: 'makelore-web-search',
|
||||
pluginId: 'makelore.web-search',
|
||||
directory: path.resolve(
|
||||
'resources/coding-plugins/web-search/skills/makelore-web-search',
|
||||
),
|
||||
}],
|
||||
});
|
||||
const effectiveResolver = {
|
||||
resolve: vi.fn(async () => ({
|
||||
accountSessionId: 'account-a\u00001',
|
||||
projectId: 'project-a',
|
||||
pluginReleaseIds: [],
|
||||
effectiveSkillIds: [],
|
||||
skillEntries: [],
|
||||
toolDefinitions: [],
|
||||
runtimePolicies: [],
|
||||
unavailableReasons: [{
|
||||
pluginId: 'makelore.web-search',
|
||||
code: 'skill_unassigned' as const,
|
||||
message: 'Plugin Skill is not assigned',
|
||||
}],
|
||||
})),
|
||||
getSkillSources: vi.fn(async () => []),
|
||||
getPolicyState: vi.fn(() => ({
|
||||
status: 'current' as const, catalog: null, revision: 1, lastVerifiedAt: 1,
|
||||
})),
|
||||
};
|
||||
const host = createCodingProductHost({
|
||||
projects: projectService(root),
|
||||
productTools: tools,
|
||||
effectiveResolver,
|
||||
getEnabledPluginIds: async () => ['makelore.web-search'],
|
||||
});
|
||||
|
||||
await expect(host.listSkills()).resolves.toContainEqual(expect.objectContaining({
|
||||
id: 'makelore-web-search', selected: false, available: true, effective: false,
|
||||
}));
|
||||
expect(effectiveResolver.resolve).not.toHaveBeenCalled();
|
||||
await expect(host.listSkills('builder')).resolves.not.toContainEqual(
|
||||
expect.objectContaining({ id: 'makelore-web-search', available: true }),
|
||||
);
|
||||
});
|
||||
|
||||
it('reads exact-run changes from the same PiProductTools tracker instance', async () => {
|
||||
const root = await configuredProject();
|
||||
await writeFile(path.join(root, 'notes.txt'), 'baseline\n', 'utf8');
|
||||
|
||||
Reference in New Issue
Block a user