mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-03 23:53:46 +00:00
Permission rework (#6319)
Co-authored-by: Github Action <action@github.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
This commit is contained in:
@@ -2,21 +2,13 @@ import path from "path"
|
||||
import z from "zod"
|
||||
import { Tool } from "./tool"
|
||||
import { Skill } from "../skill"
|
||||
import { Agent } from "../agent/agent"
|
||||
import { Permission } from "../permission"
|
||||
import { Wildcard } from "../util/wildcard"
|
||||
import { ConfigMarkdown } from "../config/markdown"
|
||||
|
||||
const parameters = z.object({
|
||||
name: z.string().describe("The skill identifier from available_skills (e.g., 'code-review')"),
|
||||
})
|
||||
export const SkillTool = Tool.define("skill", async () => {
|
||||
const skills = await Skill.all()
|
||||
|
||||
export const SkillTool: Tool.Info<typeof parameters> = {
|
||||
id: "skill",
|
||||
async init(ctx) {
|
||||
const skills = await Skill.all()
|
||||
|
||||
// Filter skills by agent permissions if agent provided
|
||||
// Filter skills by agent permissions if agent provided
|
||||
/*
|
||||
let accessibleSkills = skills
|
||||
if (ctx?.agent) {
|
||||
const permissions = ctx.agent.permission.skill
|
||||
@@ -25,81 +17,61 @@ export const SkillTool: Tool.Info<typeof parameters> = {
|
||||
return action !== "deny"
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
const description =
|
||||
accessibleSkills.length === 0
|
||||
? "Load a skill to get detailed instructions for a specific task. No skills are currently available."
|
||||
: [
|
||||
"Load a skill to get detailed instructions for a specific task.",
|
||||
"Skills provide specialized knowledge and step-by-step guidance.",
|
||||
"Use this when a task matches an available skill's description.",
|
||||
"<available_skills>",
|
||||
...accessibleSkills.flatMap((skill) => [
|
||||
` <skill>`,
|
||||
` <name>${skill.name}</name>`,
|
||||
` <description>${skill.description}</description>`,
|
||||
` </skill>`,
|
||||
]),
|
||||
"</available_skills>",
|
||||
].join(" ")
|
||||
const description =
|
||||
skills.length === 0
|
||||
? "Load a skill to get detailed instructions for a specific task. No skills are currently available."
|
||||
: [
|
||||
"Load a skill to get detailed instructions for a specific task.",
|
||||
"Skills provide specialized knowledge and step-by-step guidance.",
|
||||
"Use this when a task matches an available skill's description.",
|
||||
"<available_skills>",
|
||||
...skills.flatMap((skill) => [
|
||||
` <skill>`,
|
||||
` <name>${skill.name}</name>`,
|
||||
` <description>${skill.description}</description>`,
|
||||
` </skill>`,
|
||||
]),
|
||||
"</available_skills>",
|
||||
].join(" ")
|
||||
|
||||
return {
|
||||
description,
|
||||
parameters,
|
||||
async execute(params, ctx) {
|
||||
const agent = await Agent.get(ctx.agent)
|
||||
return {
|
||||
description,
|
||||
parameters: z.object({
|
||||
name: z
|
||||
.string()
|
||||
.describe("The skill identifier from available_skills (e.g., 'code-review' or 'category/helper')"),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
const skill = await Skill.get(params.name)
|
||||
|
||||
const skill = await Skill.get(params.name)
|
||||
if (!skill) {
|
||||
const available = Skill.all().then((x) => Object.keys(x).join(", "))
|
||||
throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
|
||||
}
|
||||
|
||||
if (!skill) {
|
||||
const available = await Skill.all().then((x) => x.map((s) => s.name).join(", "))
|
||||
throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
|
||||
}
|
||||
await ctx.ask({
|
||||
permission: "skill",
|
||||
patterns: [params.name],
|
||||
always: [params.name],
|
||||
metadata: {},
|
||||
})
|
||||
// Load and parse skill content
|
||||
const parsed = await ConfigMarkdown.parse(skill.location)
|
||||
const dir = path.dirname(skill.location)
|
||||
|
||||
// Check permission using Wildcard.all on the skill name
|
||||
const permissions = agent.permission.skill
|
||||
const action = Wildcard.all(params.name, permissions)
|
||||
// Format output similar to plugin pattern
|
||||
const output = [`## Skill: ${skill.name}`, "", `**Base directory**: ${dir}`, "", parsed.content.trim()].join("\n")
|
||||
|
||||
if (action === "deny") {
|
||||
throw new Permission.RejectedError(
|
||||
ctx.sessionID,
|
||||
"skill",
|
||||
ctx.callID,
|
||||
{ skill: params.name },
|
||||
`Access to skill "${params.name}" is denied for agent "${agent.name}".`,
|
||||
)
|
||||
}
|
||||
|
||||
if (action === "ask") {
|
||||
await Permission.ask({
|
||||
type: "skill",
|
||||
pattern: params.name,
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
callID: ctx.callID,
|
||||
title: `Load skill: ${skill.name}`,
|
||||
metadata: { name: skill.name, description: skill.description },
|
||||
})
|
||||
}
|
||||
|
||||
// Load and parse skill content
|
||||
const parsed = await ConfigMarkdown.parse(skill.location)
|
||||
const dir = path.dirname(skill.location)
|
||||
|
||||
// Format output similar to plugin pattern
|
||||
const output = [`## Skill: ${skill.name}`, "", `**Base directory**: ${dir}`, "", parsed.content.trim()].join(
|
||||
"\n",
|
||||
)
|
||||
|
||||
return {
|
||||
title: `Loaded skill: ${skill.name}`,
|
||||
output,
|
||||
metadata: {
|
||||
name: skill.name,
|
||||
dir,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
return {
|
||||
title: `Loaded skill: ${skill.name}`,
|
||||
output,
|
||||
metadata: {
|
||||
name: skill.name,
|
||||
dir,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user