171 lines
4.9 KiB
TypeScript
171 lines
4.9 KiB
TypeScript
// src/tools/skills/update-skill.ts
|
|
// Copyright (C) 2025 DTP Technologies, LLC
|
|
// All Rights Reserved
|
|
|
|
import type { ToolDefinition } from "../../lib/ai-client.js";
|
|
|
|
import {
|
|
DtpTool,
|
|
type ToolArguments,
|
|
type ToolContext,
|
|
} from "../../lib/tool.js";
|
|
import { AiSkill } from "../../models/ai-skill.js";
|
|
import { ChatSessionMode } from "../../models/chat-session.js";
|
|
import type { IUser } from "../../models/user.js";
|
|
|
|
export class UpdateSkillTool extends DtpTool {
|
|
get name(): string {
|
|
return "UpdateSkillTool";
|
|
}
|
|
get slug(): string {
|
|
return "update-skill";
|
|
}
|
|
get metadata() {
|
|
return {
|
|
name: this.definition.function.name || "update_skill",
|
|
category: "skills",
|
|
tags: ["skill", "update", "edit", "modify"],
|
|
modes: [
|
|
ChatSessionMode.Plan,
|
|
ChatSessionMode.Build,
|
|
ChatSessionMode.Test,
|
|
ChatSessionMode.Ship,
|
|
ChatSessionMode.Develop,
|
|
],
|
|
};
|
|
}
|
|
|
|
public definition: ToolDefinition = {
|
|
type: "function",
|
|
function: {
|
|
name: "update_skill",
|
|
description:
|
|
"Update an existing skill. You must know the skill ID. You can update any combination of name, description, tags, modes, and content. Only provide the fields you want to change.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
skill_id: {
|
|
type: "string",
|
|
description: "The ID of the skill to update.",
|
|
},
|
|
name: {
|
|
type: "string",
|
|
description: "New name for the skill (optional).",
|
|
},
|
|
description: {
|
|
type: "string",
|
|
description: "New description (optional).",
|
|
},
|
|
tags: {
|
|
type: "string",
|
|
description:
|
|
"New comma-separated tags (optional, replaces existing).",
|
|
},
|
|
modes: {
|
|
type: "array",
|
|
items: {
|
|
type: "string",
|
|
enum: ["build", "plan", "test", "ship", "dev"],
|
|
},
|
|
description: "New array of modes (optional, replaces existing).",
|
|
},
|
|
content: {
|
|
type: "string",
|
|
description: "New content/instructions (optional).",
|
|
},
|
|
},
|
|
required: ["skill_id"],
|
|
},
|
|
},
|
|
};
|
|
|
|
public async execute(
|
|
context: ToolContext,
|
|
args: ToolArguments,
|
|
): Promise<string> {
|
|
const skillId = args.skill_id as string | undefined;
|
|
const name = args.name as string | undefined;
|
|
const description = args.description as string | undefined;
|
|
const tagsStr = args.tags as string | undefined;
|
|
const modesArg = args.modes as string[] | undefined;
|
|
const content = args.content as string | undefined;
|
|
|
|
if (!skillId) {
|
|
return this.error("INVALID_PARAMETER", "skill_id is required.", {
|
|
parameter: "skill_id",
|
|
});
|
|
}
|
|
|
|
try {
|
|
const skill = await AiSkill.findById(skillId).lean();
|
|
if (!skill) {
|
|
return this.error("NOT_FOUND", `Skill not found: ${skillId}`);
|
|
}
|
|
|
|
const user = context.session.user as IUser;
|
|
const userId = user._id.toString();
|
|
const isOwner = skill.user?.toString() === userId;
|
|
const isGlobal = skill.user === null;
|
|
|
|
if (!isOwner && !isGlobal) {
|
|
return this.error(
|
|
"PERMISSION_DENIED",
|
|
"You can only update skills you own or global skills.",
|
|
);
|
|
}
|
|
|
|
const update: Record<string, unknown> = {};
|
|
|
|
if (name) update.name = name;
|
|
if (description) update.description = description;
|
|
if (content) update.content = content;
|
|
|
|
if (tagsStr) {
|
|
update.tags = tagsStr
|
|
.split(",")
|
|
.map((t) => t.trim())
|
|
.filter((t) => t.length > 0);
|
|
}
|
|
|
|
if (modesArg && Array.isArray(modesArg)) {
|
|
update.modes = modesArg
|
|
.map((m) => m.toLowerCase())
|
|
.filter((m) => ["build", "plan", "test", "ship", "dev"].includes(m))
|
|
.map((m) => {
|
|
switch (m) {
|
|
case "build":
|
|
return ChatSessionMode.Build;
|
|
case "plan":
|
|
return ChatSessionMode.Plan;
|
|
case "test":
|
|
return ChatSessionMode.Test;
|
|
case "ship":
|
|
return ChatSessionMode.Ship;
|
|
case "dev":
|
|
return ChatSessionMode.Develop;
|
|
default:
|
|
return ChatSessionMode.Build;
|
|
}
|
|
});
|
|
}
|
|
|
|
await AiSkill.findByIdAndUpdate(skillId, update);
|
|
|
|
const updated = await AiSkill.findById(skillId).lean();
|
|
return this.success(
|
|
{ skillId, name: updated?.name },
|
|
`Skill updated: ${updated?.name}`,
|
|
);
|
|
} catch (error) {
|
|
const errorMessage =
|
|
error instanceof Error ? error.message : String(error);
|
|
return this.error(
|
|
"OPERATION_FAILED",
|
|
`Failed to update skill: ${errorMessage}`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
export default new UpdateSkillTool();
|