refactor(agent): tighten template pre-binding contract and prune product-assistant skills

This commit is contained in:
matevip 2026-05-12 07:11:29 +08:00
parent 201e510b17
commit b74176ef66
2 changed files with 44 additions and 16 deletions

View File

@ -147,16 +147,16 @@ public class TemplateService {
// 4. Pre-bind skills the template declares so a hired agent is
// usable out of the box ("数据分析师" already knows SQL, "代码审查员"
// already has the test-driven-development playbook). Slugs are
// resolved against the target workspace; missing skills are skipped
// with a warning so a partially-installed environment can still
// complete the hire.
applyDefaultSkillBindings(template, created, workspaceId);
// already has the test-driven-development playbook). Resolution
// failures (slug missing in this workspace) are skipped with a
// warning; bind-service exceptions still propagate and roll back
// the @Transactional hire see helper Javadoc.
applyDefaultSkillBindings(template, created);
// 5. Pre-bind any standalone tools the template wants. Filtered
// against the picker so a deprecated / unavailable tool name in the
// template doesn't abort the hire same forgiving stance as
// skills above.
// 5. Pre-bind any standalone tools the template wants. Picker
// outage and unknown names are dropped with a warning; a
// setToolBindings exception still propagates (same contract as
// skills) see helper Javadoc.
applyDefaultToolBindings(template, created);
return created;
@ -164,15 +164,39 @@ public class TemplateService {
/**
* Resolve {@link TemplateDTO#getDefaultSkillSlugs()} to skill ids inside
* {@code workspaceId} and pre-bind them on the freshly-created agent.
* Slugs whose row is missing in the workspace are logged and dropped a
* template MUST be safe to apply even when some bundled skills haven't
* landed yet (offline upgrade, partial seed, custom workspace).
* the agent's own workspace and pre-bind them.
*
* <p><b>Failure contract read carefully.</b>
* <ul>
* <li><b>Resolution failures</b> (slug not present in the agent's
* workspace, blank entries) logged and dropped. A template MUST
* stay applyable on an offline upgrade or partial-seed install
* where some bundled skills haven't landed yet.</li>
* <li><b>Service-layer failures</b>
* ({@link AgentBindingService#setSkillBindings} throws e.g. a
* race deletes the skill row between resolve and bind, or the
* workspace check rejects it) <em>propagate</em>. Because
* {@link #applyTemplate} runs under {@code @Transactional}, this
* rolls back the whole hire. That's deliberate: such a throw is
* a real wiring/race problem, and pretending the hire succeeded
* would leave the user with a half-configured agent.</li>
* </ul>
*
* <p>Reads the workspace off the just-persisted {@link AgentEntity}
* rather than a separate parameter so the lookup and the validator
* inside {@code AgentBindingService.requireSameWorkspace} can never
* disagree on which workspace they're talking about.
*/
private void applyDefaultSkillBindings(TemplateDTO template, AgentEntity created, Long workspaceId) {
private void applyDefaultSkillBindings(TemplateDTO template, AgentEntity created) {
List<String> slugs = template.getDefaultSkillSlugs();
if (slugs == null || slugs.isEmpty()) return;
// Mirror the fallback inside AgentBindingService.requireSameWorkspace:
// a null workspace_id on a row is treated as workspace 1, so the
// lookup needs to agree or we'd silently turn `eq(workspaceId, null)`
// into `IS NULL` and match nothing.
Long workspaceId = created.getWorkspaceId() == null ? 1L : created.getWorkspaceId();
List<Long> resolvedIds = new ArrayList<>();
for (String slug : slugs) {
if (slug == null || slug.isBlank()) continue;
@ -198,6 +222,11 @@ public class TemplateService {
* {@link AgentBindingService#setToolBindings} sees only resolvable names
* its own validation would otherwise abort the call on the first
* unknown name and leave the agent with no tool bindings at all.
*
* <p>Failure contract mirrors {@link #applyDefaultSkillBindings}:
* picker outage and unknown names are dropped with a warning; an
* exception from {@code setToolBindings} itself still propagates and
* rolls back the hire.
*/
private void applyDefaultToolBindings(TemplateDTO template, AgentEntity created) {
List<String> names = template.getDefaultToolNames();

View File

@ -10,8 +10,7 @@
"maxIterations": 12,
"defaultSkillSlugs": [
"ideation",
"make_plan",
"writing-plans"
"make_plan"
],
"systemPrompt": "## Role\n产品助理\n\n## Goal\n把模糊需求理成可执行的 PRD\n\n## Backstory\n你做产品做久了知道一句话需求背后通常藏着三个不一样的问题。所以你拿到任何描述先把它翻译成\"用户是谁 + 他在什么场景下 + 他想达成什么 + 现在的痛点是什么\"。你写 PRD 不堆功能列表,会先讲清楚\"不做什么\"和\"成功长什么样\"。\n\n## Additional Instructions\n输出结构1) 用户与场景2) 目标与反目标不做什么3) 核心流程4) 验收标准。一段话能讲清的不用列表,能列清的不用图。讲清楚\"为什么\"比讲清楚\"做什么\"更重要。\n",
"workspaceFiles": [