@aigne/core 1.72.0-beta.2 → 1.72.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/lib/cjs/agents/agent.d.ts +31 -1
- package/lib/cjs/agents/agent.js +13 -0
- package/lib/cjs/agents/ai-agent.d.ts +7 -0
- package/lib/cjs/agents/ai-agent.js +85 -3
- package/lib/cjs/agents/chat-model.d.ts +153 -0
- package/lib/cjs/agents/chat-model.js +35 -1
- package/lib/cjs/agents/image-agent.d.ts +17 -1
- package/lib/cjs/agents/image-agent.js +16 -0
- package/lib/cjs/agents/image-model.d.ts +14 -4
- package/lib/cjs/agents/mcp-agent.d.ts +17 -0
- package/lib/cjs/agents/mcp-agent.js +18 -0
- package/lib/cjs/agents/team-agent.d.ts +55 -0
- package/lib/cjs/agents/team-agent.js +31 -0
- package/lib/cjs/agents/transform-agent.d.ts +12 -0
- package/lib/cjs/agents/transform-agent.js +13 -0
- package/lib/cjs/agents/video-model.d.ts +14 -4
- package/lib/cjs/aigne/usage.d.ts +4 -0
- package/lib/cjs/aigne/usage.js +6 -0
- package/lib/cjs/loader/agent-yaml.d.ts +5 -63
- package/lib/cjs/loader/agent-yaml.js +4 -129
- package/lib/cjs/loader/agents.d.ts +4 -0
- package/lib/cjs/loader/agents.js +17 -0
- package/lib/cjs/loader/index.d.ts +18 -14
- package/lib/cjs/loader/index.js +20 -81
- package/lib/cjs/loader/schema.d.ts +21 -6
- package/lib/cjs/loader/schema.js +60 -1
- package/lib/cjs/prompt/prompt-builder.js +0 -1
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.d.ts +17 -0
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.js +63 -0
- package/lib/cjs/prompt/skills/afs/agent-skill/skill-loader.d.ts +13 -0
- package/lib/cjs/prompt/skills/afs/agent-skill/skill-loader.js +61 -0
- package/lib/cjs/prompt/skills/afs/delete.js +15 -3
- package/lib/cjs/prompt/skills/afs/edit.js +30 -7
- package/lib/cjs/prompt/skills/afs/exec.js +17 -6
- package/lib/cjs/prompt/skills/afs/index.js +4 -1
- package/lib/cjs/prompt/skills/afs/list.js +26 -10
- package/lib/cjs/prompt/skills/afs/read.js +14 -3
- package/lib/cjs/prompt/skills/afs/rename.js +18 -4
- package/lib/cjs/prompt/skills/afs/search.js +21 -5
- package/lib/cjs/prompt/skills/afs/write.js +18 -4
- package/lib/cjs/prompt/template.d.ts +92 -17
- package/lib/cjs/prompt/template.js +46 -17
- package/lib/dts/agents/agent.d.ts +31 -1
- package/lib/dts/agents/ai-agent.d.ts +7 -0
- package/lib/dts/agents/chat-model.d.ts +153 -0
- package/lib/dts/agents/image-agent.d.ts +17 -1
- package/lib/dts/agents/image-model.d.ts +14 -4
- package/lib/dts/agents/mcp-agent.d.ts +17 -0
- package/lib/dts/agents/team-agent.d.ts +55 -0
- package/lib/dts/agents/transform-agent.d.ts +12 -0
- package/lib/dts/agents/video-model.d.ts +14 -4
- package/lib/dts/aigne/context.d.ts +2 -2
- package/lib/dts/aigne/usage.d.ts +4 -0
- package/lib/dts/loader/agent-yaml.d.ts +5 -63
- package/lib/dts/loader/agents.d.ts +4 -0
- package/lib/dts/loader/index.d.ts +18 -14
- package/lib/dts/loader/schema.d.ts +21 -6
- package/lib/dts/prompt/skills/afs/agent-skill/agent-skill.d.ts +17 -0
- package/lib/dts/prompt/skills/afs/agent-skill/skill-loader.d.ts +13 -0
- package/lib/dts/prompt/template.d.ts +92 -17
- package/lib/esm/agents/agent.d.ts +31 -1
- package/lib/esm/agents/agent.js +13 -0
- package/lib/esm/agents/ai-agent.d.ts +7 -0
- package/lib/esm/agents/ai-agent.js +85 -3
- package/lib/esm/agents/chat-model.d.ts +153 -0
- package/lib/esm/agents/chat-model.js +34 -0
- package/lib/esm/agents/image-agent.d.ts +17 -1
- package/lib/esm/agents/image-agent.js +16 -0
- package/lib/esm/agents/image-model.d.ts +14 -4
- package/lib/esm/agents/mcp-agent.d.ts +17 -0
- package/lib/esm/agents/mcp-agent.js +18 -0
- package/lib/esm/agents/team-agent.d.ts +55 -0
- package/lib/esm/agents/team-agent.js +31 -0
- package/lib/esm/agents/transform-agent.d.ts +12 -0
- package/lib/esm/agents/transform-agent.js +13 -0
- package/lib/esm/agents/video-model.d.ts +14 -4
- package/lib/esm/aigne/context.d.ts +2 -2
- package/lib/esm/aigne/usage.d.ts +4 -0
- package/lib/esm/aigne/usage.js +6 -0
- package/lib/esm/loader/agent-yaml.d.ts +5 -63
- package/lib/esm/loader/agent-yaml.js +4 -128
- package/lib/esm/loader/agents.d.ts +4 -0
- package/lib/esm/loader/agents.js +14 -0
- package/lib/esm/loader/index.d.ts +18 -14
- package/lib/esm/loader/index.js +21 -81
- package/lib/esm/loader/schema.d.ts +21 -6
- package/lib/esm/loader/schema.js +57 -0
- package/lib/esm/prompt/prompt-builder.js +1 -2
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.d.ts +17 -0
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.js +59 -0
- package/lib/esm/prompt/skills/afs/agent-skill/skill-loader.d.ts +13 -0
- package/lib/esm/prompt/skills/afs/agent-skill/skill-loader.js +53 -0
- package/lib/esm/prompt/skills/afs/delete.js +15 -3
- package/lib/esm/prompt/skills/afs/edit.js +30 -7
- package/lib/esm/prompt/skills/afs/exec.js +17 -6
- package/lib/esm/prompt/skills/afs/index.js +4 -1
- package/lib/esm/prompt/skills/afs/list.js +26 -10
- package/lib/esm/prompt/skills/afs/read.js +14 -3
- package/lib/esm/prompt/skills/afs/rename.js +18 -4
- package/lib/esm/prompt/skills/afs/search.js +21 -5
- package/lib/esm/prompt/skills/afs/write.js +18 -4
- package/lib/esm/prompt/template.d.ts +92 -17
- package/lib/esm/prompt/template.js +46 -17
- package/package.json +5 -4
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ZodType, z } from "zod";
|
|
2
|
+
import { type Role } from "../agents/chat-model.js";
|
|
3
|
+
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
2
4
|
export declare const inputOutputSchema: ({ path }: {
|
|
3
5
|
path: string;
|
|
4
6
|
}) => z.ZodUnion<[ZodType<any, z.ZodTypeDef, any>, z.ZodEffects<z.ZodObject<{
|
|
@@ -55,9 +57,9 @@ declare const chatModelObjectSchema: z.ZodObject<{
|
|
|
55
57
|
} | undefined, z.ZodTypeDef, number | {
|
|
56
58
|
$get: string;
|
|
57
59
|
} | undefined>;
|
|
58
|
-
thinkingEffort: ZodType<number | "high" | "
|
|
60
|
+
thinkingEffort: ZodType<number | "high" | "low" | "medium" | "minimal" | {
|
|
59
61
|
$get: string;
|
|
60
|
-
} | undefined, z.ZodTypeDef, number | "high" | "
|
|
62
|
+
} | undefined, z.ZodTypeDef, number | "high" | "low" | "medium" | "minimal" | {
|
|
61
63
|
$get: string;
|
|
62
64
|
} | undefined>;
|
|
63
65
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
@@ -86,9 +88,9 @@ declare const chatModelObjectSchema: z.ZodObject<{
|
|
|
86
88
|
} | undefined, z.ZodTypeDef, number | {
|
|
87
89
|
$get: string;
|
|
88
90
|
} | undefined>;
|
|
89
|
-
thinkingEffort: ZodType<number | "high" | "
|
|
91
|
+
thinkingEffort: ZodType<number | "high" | "low" | "medium" | "minimal" | {
|
|
90
92
|
$get: string;
|
|
91
|
-
} | undefined, z.ZodTypeDef, number | "high" | "
|
|
93
|
+
} | undefined, z.ZodTypeDef, number | "high" | "low" | "medium" | "minimal" | {
|
|
92
94
|
$get: string;
|
|
93
95
|
} | undefined>;
|
|
94
96
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
@@ -117,9 +119,9 @@ declare const chatModelObjectSchema: z.ZodObject<{
|
|
|
117
119
|
} | undefined, z.ZodTypeDef, number | {
|
|
118
120
|
$get: string;
|
|
119
121
|
} | undefined>;
|
|
120
|
-
thinkingEffort: ZodType<number | "high" | "
|
|
122
|
+
thinkingEffort: ZodType<number | "high" | "low" | "medium" | "minimal" | {
|
|
121
123
|
$get: string;
|
|
122
|
-
} | undefined, z.ZodTypeDef, number | "high" | "
|
|
124
|
+
} | undefined, z.ZodTypeDef, number | "high" | "low" | "medium" | "minimal" | {
|
|
123
125
|
$get: string;
|
|
124
126
|
} | undefined>;
|
|
125
127
|
}, z.ZodTypeAny, "passthrough">>;
|
|
@@ -149,4 +151,17 @@ export declare function camelizeSchema<T extends ZodType>(schema: T, { shallow }
|
|
|
149
151
|
shallow?: boolean;
|
|
150
152
|
}): T;
|
|
151
153
|
export declare function preprocessSchema<T extends ZodType>(fn: (data: unknown) => unknown, schema: T): T;
|
|
154
|
+
export type Instructions = {
|
|
155
|
+
role: Exclude<Role, "tool">;
|
|
156
|
+
content: string;
|
|
157
|
+
path: string;
|
|
158
|
+
cacheControl?: {
|
|
159
|
+
type: "ephemeral";
|
|
160
|
+
ttl?: "5m" | "1h";
|
|
161
|
+
};
|
|
162
|
+
}[];
|
|
163
|
+
export declare const getInstructionsSchema: ({ filepath }: {
|
|
164
|
+
filepath: string;
|
|
165
|
+
}) => ZodType<Instructions>;
|
|
166
|
+
export declare function instructionsToPromptBuilder(instructions: Instructions | string): PromptBuilder;
|
|
152
167
|
export {};
|
package/lib/esm/loader/schema.js
CHANGED
|
@@ -2,6 +2,9 @@ import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
|
2
2
|
import { parse } from "yaml";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { getterSchema } from "../agents/agent.js";
|
|
5
|
+
import { roleSchema } from "../agents/chat-model.js";
|
|
6
|
+
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
7
|
+
import { ChatMessagesTemplate, parseChatMessages } from "../prompt/template.js";
|
|
5
8
|
import { camelize } from "../utils/camelize.js";
|
|
6
9
|
import { isRecord } from "../utils/type-utils.js";
|
|
7
10
|
export const inputOutputSchema = ({ path }) => {
|
|
@@ -94,3 +97,57 @@ export function camelizeSchema(schema, { shallow = true } = {}) {
|
|
|
94
97
|
export function preprocessSchema(fn, schema) {
|
|
95
98
|
return z.preprocess(fn, schema);
|
|
96
99
|
}
|
|
100
|
+
const instructionItemSchema = camelizeSchema(z.union([
|
|
101
|
+
z.object({
|
|
102
|
+
role: roleSchema.default("system"),
|
|
103
|
+
url: z.string(),
|
|
104
|
+
cacheControl: optionalize(z.object({
|
|
105
|
+
type: z.literal("ephemeral"),
|
|
106
|
+
ttl: optionalize(z.union([z.literal("5m"), z.literal("1h")])),
|
|
107
|
+
})),
|
|
108
|
+
}),
|
|
109
|
+
z.object({
|
|
110
|
+
role: roleSchema.default("system"),
|
|
111
|
+
content: z.string(),
|
|
112
|
+
cacheControl: optionalize(z.object({
|
|
113
|
+
type: z.literal("ephemeral"),
|
|
114
|
+
ttl: optionalize(z.union([z.literal("5m"), z.literal("1h")])),
|
|
115
|
+
})),
|
|
116
|
+
}),
|
|
117
|
+
]));
|
|
118
|
+
const parseInstructionItem = ({ filepath }) => async ({ role, cacheControl, ...v }) => {
|
|
119
|
+
if (role === "tool")
|
|
120
|
+
throw new Error(`'tool' role is not allowed in instruction item in agent file ${filepath}`);
|
|
121
|
+
if ("content" in v && typeof v.content === "string") {
|
|
122
|
+
return { role, content: v.content, path: filepath, cacheControl };
|
|
123
|
+
}
|
|
124
|
+
if ("url" in v && typeof v.url === "string") {
|
|
125
|
+
const url = nodejs.path.isAbsolute(v.url)
|
|
126
|
+
? v.url
|
|
127
|
+
: nodejs.path.join(nodejs.path.dirname(filepath), v.url);
|
|
128
|
+
return nodejs.fs
|
|
129
|
+
.readFile(url, "utf8")
|
|
130
|
+
.then((content) => ({ role, content, path: url, cacheControl }));
|
|
131
|
+
}
|
|
132
|
+
throw new Error(`Invalid instruction item in agent file ${filepath}. Expected 'content' or 'url' property`);
|
|
133
|
+
};
|
|
134
|
+
export const getInstructionsSchema = ({ filepath }) => z
|
|
135
|
+
.union([z.string(), instructionItemSchema, z.array(instructionItemSchema)])
|
|
136
|
+
.transform(async (v) => {
|
|
137
|
+
if (typeof v === "string")
|
|
138
|
+
return [{ role: "system", content: v, path: filepath }];
|
|
139
|
+
if (Array.isArray(v)) {
|
|
140
|
+
return Promise.all(v.map((item) => parseInstructionItem({ filepath })(item)));
|
|
141
|
+
}
|
|
142
|
+
return [await parseInstructionItem({ filepath })(v)];
|
|
143
|
+
});
|
|
144
|
+
export function instructionsToPromptBuilder(instructions) {
|
|
145
|
+
return new PromptBuilder({
|
|
146
|
+
instructions: typeof instructions === "string"
|
|
147
|
+
? instructions
|
|
148
|
+
: ChatMessagesTemplate.from(parseChatMessages(instructions.map((i) => ({
|
|
149
|
+
...i,
|
|
150
|
+
options: { workingDir: nodejs.path.dirname(i.path) },
|
|
151
|
+
})))),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
@@ -10,7 +10,7 @@ import { optionalize } from "../loader/schema.js";
|
|
|
10
10
|
import { outputSchemaToResponseFormatSchema } from "../utils/json-schema.js";
|
|
11
11
|
import { checkArguments, flat, isNonNullable, isRecord, partition, unique, } from "../utils/type-utils.js";
|
|
12
12
|
import { createPromptBuilderContext } from "./context/index.js";
|
|
13
|
-
import { AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE
|
|
13
|
+
import { AFS_EXECUTABLE_TOOLS_PROMPT_TEMPLATE } from "./prompts/afs-builtin-prompt.js";
|
|
14
14
|
import { MEMORY_MESSAGE_TEMPLATE } from "./prompts/memory-message-template.js";
|
|
15
15
|
import { STRUCTURED_STREAM_INSTRUCTIONS } from "./prompts/structured-stream-instructions.js";
|
|
16
16
|
import { getAFSSkills } from "./skills/afs/index.js";
|
|
@@ -116,7 +116,6 @@ export class PromptBuilder {
|
|
|
116
116
|
const afs = options.agent?.afs;
|
|
117
117
|
if (afs && options.agent?.historyConfig?.disabled !== true) {
|
|
118
118
|
const historyModule = (await afs.listModules()).find((m) => m.module instanceof AFSHistory);
|
|
119
|
-
messages.push(await SystemMessageTemplate.from(await getAFSSystemPrompt(afs)).format({}));
|
|
120
119
|
if (historyModule) {
|
|
121
120
|
const history = await afs.list(historyModule.path, {
|
|
122
121
|
limit: options.agent?.maxRetrieveMemoryCount || 10,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Agent, type AgentOptions, type Message } from "../../../../agents/agent.js";
|
|
2
|
+
import type { Skill } from "./skill-loader.js";
|
|
3
|
+
export interface SkillToolInput extends Message {
|
|
4
|
+
skill: string;
|
|
5
|
+
args?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SkillToolOutput extends Message {
|
|
8
|
+
result: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SkillToolOptions extends AgentOptions<SkillToolInput, SkillToolOutput> {
|
|
11
|
+
agentSkills: Skill[];
|
|
12
|
+
}
|
|
13
|
+
export declare class AgentSkill extends Agent<SkillToolInput, SkillToolOutput> {
|
|
14
|
+
constructor(options: SkillToolOptions);
|
|
15
|
+
private agentSkills;
|
|
16
|
+
process(input: SkillToolInput): Promise<SkillToolOutput>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Agent } from "../../../../agents/agent.js";
|
|
3
|
+
const skillToolInputSchema = z.object({
|
|
4
|
+
skill: z.string().describe("The name of the skill agent to invoke."),
|
|
5
|
+
args: z.string().optional().describe("The arguments to pass to the skill."),
|
|
6
|
+
});
|
|
7
|
+
export class AgentSkill extends Agent {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super({
|
|
10
|
+
name: "Skill",
|
|
11
|
+
taskTitle: "Invoke {{skill}}: {{args}}",
|
|
12
|
+
...options,
|
|
13
|
+
description: `\
|
|
14
|
+
Execute a skill within the main conversation
|
|
15
|
+
|
|
16
|
+
<skills_instructions>
|
|
17
|
+
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
|
|
18
|
+
|
|
19
|
+
When users ask you to run a "slash command" or reference "/" (e.g., "/commit", "/review-pr"), they are referring to a skill. Use this tool to invoke the corresponding skill.
|
|
20
|
+
|
|
21
|
+
User: "run /commit" Assistant: [Calls Skill tool with skill: "commit"]
|
|
22
|
+
How to invoke:
|
|
23
|
+
|
|
24
|
+
Use this tool with the skill name and optional arguments
|
|
25
|
+
|
|
26
|
+
Important:
|
|
27
|
+
|
|
28
|
+
When a skill is relevant, you must invoke this tool IMMEDIATELY as your first action
|
|
29
|
+
NEVER just announce or mention a skill in your text response without actually calling this tool
|
|
30
|
+
This is a BLOCKING REQUIREMENT: invoke the relevant Skill tool BEFORE generating any other response about the task
|
|
31
|
+
Only use skills listed in <available_skills> below
|
|
32
|
+
Do not invoke a skill that is already running
|
|
33
|
+
Do not use this tool for built-in CLI commands (like /help, /clear, etc.)
|
|
34
|
+
</skills_instructions>
|
|
35
|
+
|
|
36
|
+
<available_skills>
|
|
37
|
+
${options.agentSkills.map((s) => `${s.name}: ${s.description}`).join("\n\n")}
|
|
38
|
+
</available_skills>
|
|
39
|
+
`,
|
|
40
|
+
inputSchema: skillToolInputSchema,
|
|
41
|
+
});
|
|
42
|
+
this.agentSkills = options.agentSkills;
|
|
43
|
+
}
|
|
44
|
+
agentSkills;
|
|
45
|
+
async process(input) {
|
|
46
|
+
const skill = this.agentSkills.find((s) => s.name === input.skill);
|
|
47
|
+
if (!skill)
|
|
48
|
+
throw new Error(`Skill not found: ${input.skill}`);
|
|
49
|
+
return {
|
|
50
|
+
result: `\
|
|
51
|
+
Base directory for this skill: ${skill.path}
|
|
52
|
+
|
|
53
|
+
${skill.content}
|
|
54
|
+
|
|
55
|
+
${input.args ? `ARGUMENTS: ${input.args ?? "None"}` : ""}
|
|
56
|
+
`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AFS } from "@aigne/afs";
|
|
2
|
+
import { AgentSkill } from "./agent-skill.js";
|
|
3
|
+
export interface Skill {
|
|
4
|
+
path: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadSkill(path: string): Promise<Skill>;
|
|
10
|
+
export declare function loadSkills(paths: string[]): Promise<Skill[]>;
|
|
11
|
+
export declare function loadAgentSkillFromAFS({ afs, }: {
|
|
12
|
+
afs: AFS;
|
|
13
|
+
}): Promise<AgentSkill | undefined>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
|
+
import fm from "front-matter";
|
|
3
|
+
import { AgentSkill } from "./agent-skill.js";
|
|
4
|
+
function parseSkill(content, path) {
|
|
5
|
+
const meta = fm(content);
|
|
6
|
+
return {
|
|
7
|
+
path,
|
|
8
|
+
name: meta.attributes.name,
|
|
9
|
+
description: meta.attributes.description,
|
|
10
|
+
content: meta.body,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export async function loadSkill(path) {
|
|
14
|
+
const entry = nodejs.path.join(path, "SKILL.md");
|
|
15
|
+
const skill = await nodejs.fs.readFile(entry, "utf-8");
|
|
16
|
+
return parseSkill(skill, path);
|
|
17
|
+
}
|
|
18
|
+
export async function loadSkills(paths) {
|
|
19
|
+
const skills = [];
|
|
20
|
+
for (const path of paths) {
|
|
21
|
+
const skill = await loadSkill(path);
|
|
22
|
+
skills.push(skill);
|
|
23
|
+
}
|
|
24
|
+
return skills;
|
|
25
|
+
}
|
|
26
|
+
export async function loadAgentSkillFromAFS({ afs, }) {
|
|
27
|
+
const modules = await afs.listModules();
|
|
28
|
+
const filtered = modules.filter(({ module: m }) => "options" in m &&
|
|
29
|
+
typeof m.options === "object" &&
|
|
30
|
+
m.options &&
|
|
31
|
+
"agentSkills" in m.options &&
|
|
32
|
+
m.options.agentSkills === true);
|
|
33
|
+
if (!filtered.length)
|
|
34
|
+
return;
|
|
35
|
+
const skills = [];
|
|
36
|
+
for (const module of filtered) {
|
|
37
|
+
const data = (await afs.list(module.path, {
|
|
38
|
+
pattern: "**/SKILL.md",
|
|
39
|
+
})).data;
|
|
40
|
+
for (const entry of data) {
|
|
41
|
+
const { data: file } = await afs.read(entry.path);
|
|
42
|
+
if (typeof file?.content !== "string")
|
|
43
|
+
continue;
|
|
44
|
+
const skill = parseSkill(file.content, nodejs.path.dirname(entry.path));
|
|
45
|
+
skills.push(skill);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!skills.length)
|
|
49
|
+
return;
|
|
50
|
+
return new AgentSkill({
|
|
51
|
+
agentSkills: skills,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -4,15 +4,27 @@ export class AFSDeleteAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_delete",
|
|
7
|
-
description:
|
|
7
|
+
description: `Permanently delete files or directories from the Agentic File System (AFS)
|
|
8
|
+
- Removes files or directories at the specified AFS path
|
|
9
|
+
- Supports recursive deletion for directories with contents
|
|
10
|
+
- Use with caution as deletion is permanent
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/docs/old-file.md", "/temp")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- To delete a directory, you MUST set recursive=true
|
|
16
|
+
- Deleting a non-empty directory without recursive=true will fail
|
|
17
|
+
- This operation cannot be undone`,
|
|
8
18
|
...options,
|
|
9
19
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
20
|
+
path: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Absolute AFS path to delete (e.g., '/docs/old-file.md', '/temp'). Must start with '/'"),
|
|
11
23
|
recursive: z
|
|
12
24
|
.boolean()
|
|
13
25
|
.optional()
|
|
14
26
|
.default(false)
|
|
15
|
-
.describe("
|
|
27
|
+
.describe("MUST be set to true to delete directories. Default: false (files only)"),
|
|
16
28
|
}),
|
|
17
29
|
outputSchema: z.object({
|
|
18
30
|
status: z.string(),
|
|
@@ -4,19 +4,42 @@ export class AFSEditAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_edit",
|
|
7
|
-
description:
|
|
7
|
+
description: `Apply precise line-based patches to modify files in the Agentic File System (AFS)
|
|
8
|
+
- Performs targeted edits using line numbers without rewriting the entire file
|
|
9
|
+
- Supports both replacing and deleting line ranges
|
|
10
|
+
- Multiple patches can be applied in a single operation
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/docs/readme.md")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- IMPORTANT: You MUST use afs_read with withLineNumbers=true before editing to get accurate line numbers
|
|
16
|
+
- Line numbers are 0-based: first line is 0, second line is 1, etc.
|
|
17
|
+
- The range [start_line, end_line) is exclusive on end_line`,
|
|
8
18
|
...options,
|
|
9
19
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
20
|
+
path: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Absolute AFS path to the file to edit (e.g., '/docs/readme.md'). Must start with '/'"),
|
|
11
23
|
patches: z
|
|
12
24
|
.array(z.object({
|
|
13
|
-
start_line: z
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
start_line: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.describe("Start line number (0-based, inclusive). First line is 0"),
|
|
29
|
+
end_line: z
|
|
30
|
+
.number()
|
|
31
|
+
.int()
|
|
32
|
+
.describe("End line number (0-based, exclusive). To edit line 5 only, use start_line=5, end_line=6"),
|
|
33
|
+
replace: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("New content to insert. Omit when delete=true"),
|
|
37
|
+
delete: z
|
|
38
|
+
.boolean()
|
|
39
|
+
.describe("Set to true to delete the line range. Set to false to replace with 'replace' content"),
|
|
17
40
|
}))
|
|
18
41
|
.min(1)
|
|
19
|
-
.describe("
|
|
42
|
+
.describe("Array of patches to apply. Each patch specifies a line range and the operation (delete or replace)"),
|
|
20
43
|
}),
|
|
21
44
|
outputSchema: z.object({
|
|
22
45
|
status: z.string(),
|
|
@@ -4,14 +4,25 @@ export class AFSExecAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_exec",
|
|
7
|
-
description: `
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
description: `Execute files marked as executable in the Agentic File System (AFS)
|
|
8
|
+
- Runs executable entries (functions, agents, skills) registered at a given AFS path
|
|
9
|
+
- Passes arguments to the executable and returns its output
|
|
10
|
+
- Use this to invoke dynamic functionality stored in AFS
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- The path must be an absolute AFS path to an executable entry (e.g., "/skills/summarize", "/agents/translator")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- Use afs_list to discover available executables (look for entries with execute metadata)
|
|
16
|
+
- Arguments must be a valid JSON string matching the executable's input schema
|
|
17
|
+
- The executable's input/output schema can be found in its metadata`,
|
|
11
18
|
...options,
|
|
12
19
|
inputSchema: z.object({
|
|
13
|
-
path: z
|
|
14
|
-
|
|
20
|
+
path: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Absolute AFS path to the executable (e.g., '/skills/summarize'). Must start with '/'"),
|
|
23
|
+
args: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe('JSON string of arguments matching the executable\'s input schema (e.g., \'{"text": "hello"}\')'),
|
|
15
26
|
}),
|
|
16
27
|
outputSchema: z.object({
|
|
17
28
|
data: z.record(z.any()),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isNonNullable } from "../../../utils/type-utils.js";
|
|
2
|
+
import { loadAgentSkillFromAFS } from "./agent-skill/skill-loader.js";
|
|
1
3
|
import { AFSDeleteAgent } from "./delete.js";
|
|
2
4
|
import { AFSEditAgent } from "./edit.js";
|
|
3
5
|
import { AFSExecAgent } from "./exec.js";
|
|
@@ -16,5 +18,6 @@ export async function getAFSSkills(afs) {
|
|
|
16
18
|
new AFSDeleteAgent({ afs }),
|
|
17
19
|
new AFSRenameAgent({ afs }),
|
|
18
20
|
new AFSExecAgent({ afs }),
|
|
19
|
-
|
|
21
|
+
await loadAgentSkillFromAFS({ afs }),
|
|
22
|
+
].filter(isNonNullable);
|
|
20
23
|
}
|
|
@@ -4,26 +4,42 @@ export class AFSListAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_list",
|
|
7
|
-
description:
|
|
7
|
+
description: `List contents within the Agentic File System (AFS)
|
|
8
|
+
- Returns files and directories at the specified AFS path
|
|
9
|
+
- Supports recursive listing with configurable depth
|
|
10
|
+
- Supports glob pattern filtering to match specific files
|
|
11
|
+
- By default respects .gitignore rules to filter out ignored files
|
|
12
|
+
- Use this tool when you need to explore AFS contents or understand file organization
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/", "/docs", "/memory/user")
|
|
16
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
17
|
+
- Use maxDepth to control recursion depth (default: 1, current directory only)
|
|
18
|
+
- Use pattern to filter entries by glob pattern:
|
|
19
|
+
- "*.ts" - match TypeScript files in current directory
|
|
20
|
+
- "**/*.js" - match all JavaScript files recursively
|
|
21
|
+
- "src/**/*.{ts,tsx}" - match TypeScript files in src directory
|
|
22
|
+
- Results are filtered by .gitignore by default; set disableGitignore to include ignored files`,
|
|
8
23
|
...options,
|
|
9
24
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
25
|
+
path: z
|
|
26
|
+
.string()
|
|
27
|
+
.describe("Absolute AFS path to list (e.g., '/', '/docs', '/memory/user'). Must start with '/'"),
|
|
11
28
|
options: z
|
|
12
29
|
.object({
|
|
13
|
-
maxDepth: z
|
|
30
|
+
maxDepth: z
|
|
31
|
+
.number()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Maximum depth of directory recursion. 1 = current directory only, 2 = include subdirectories, etc. Default: 1"),
|
|
14
34
|
disableGitignore: z
|
|
15
35
|
.boolean()
|
|
16
36
|
.optional()
|
|
17
|
-
.describe("
|
|
37
|
+
.describe("Set to true to include files normally ignored by .gitignore rules. Default: false (respects .gitignore)"),
|
|
18
38
|
maxChildren: z
|
|
19
39
|
.number()
|
|
20
40
|
.optional()
|
|
21
|
-
.describe("Maximum number of
|
|
22
|
-
|
|
23
|
-
.union([z.literal("simple-list"), z.literal("tree")])
|
|
24
|
-
.optional()
|
|
25
|
-
.default("simple-list")
|
|
26
|
-
.describe("Output format, either 'simple-list', or 'tree', default is 'simple-list'"),
|
|
41
|
+
.describe("Maximum number of entries to return per directory. Useful for large directories to avoid overwhelming output"),
|
|
42
|
+
pattern: z.string().optional().describe("Glob pattern to filter entries by path"),
|
|
27
43
|
})
|
|
28
44
|
.optional(),
|
|
29
45
|
}),
|
|
@@ -4,14 +4,25 @@ export class AFSReadAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_read",
|
|
7
|
-
description:
|
|
7
|
+
description: `Read file contents from the Agentic File System (AFS)
|
|
8
|
+
- Returns the complete content of a file at the specified AFS path
|
|
9
|
+
- Supports line numbers output for precise editing references
|
|
10
|
+
- Use this tool when you need to review, analyze, or understand file content
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/docs/readme.md", "/memory/user/notes")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- IMPORTANT: You MUST set withLineNumbers to true before using afs_edit, as line numbers are required for precise edits
|
|
16
|
+
- Returns the file's content along with metadata (id, path, timestamps, etc.)`,
|
|
8
17
|
...options,
|
|
9
18
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
19
|
+
path: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe("Absolute AFS path to the file to read (e.g., '/docs/readme.md'). Must start with '/'"),
|
|
11
22
|
withLineNumbers: z
|
|
12
23
|
.boolean()
|
|
13
24
|
.optional()
|
|
14
|
-
.describe("
|
|
25
|
+
.describe("MUST be set to true before using afs_edit. Adds line numbers to output (format: '1| line content')"),
|
|
15
26
|
}),
|
|
16
27
|
outputSchema: z.object({
|
|
17
28
|
status: z.string(),
|
|
@@ -4,16 +4,30 @@ export class AFSRenameAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_rename",
|
|
7
|
-
description:
|
|
7
|
+
description: `Rename or move files and directories within the Agentic File System (AFS)
|
|
8
|
+
- Renames a file or directory to a new name
|
|
9
|
+
- Can also move files/directories to a different location
|
|
10
|
+
- Optionally overwrites existing files at the destination
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- Both paths must be absolute AFS paths starting with "/" (e.g., "/docs/old-name.md" -> "/docs/new-name.md")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- To move a file, specify a different directory in newPath (e.g., "/docs/file.md" -> "/archive/file.md")
|
|
16
|
+
- If newPath already exists, the operation will fail unless overwrite=true
|
|
17
|
+
- Moving directories moves all contents recursively`,
|
|
8
18
|
...options,
|
|
9
19
|
inputSchema: z.object({
|
|
10
|
-
oldPath: z
|
|
11
|
-
|
|
20
|
+
oldPath: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Current absolute AFS path (e.g., '/docs/old-name.md'). Must start with '/'"),
|
|
23
|
+
newPath: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe("New absolute AFS path (e.g., '/docs/new-name.md'). Must start with '/'"),
|
|
12
26
|
overwrite: z
|
|
13
27
|
.boolean()
|
|
14
28
|
.optional()
|
|
15
29
|
.default(false)
|
|
16
|
-
.describe("
|
|
30
|
+
.describe("Set to true to overwrite if destination already exists. Default: false (fails if exists)"),
|
|
17
31
|
}),
|
|
18
32
|
outputSchema: z.object({
|
|
19
33
|
status: z.string(),
|
|
@@ -4,18 +4,34 @@ export class AFSSearchAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_search",
|
|
7
|
-
description:
|
|
7
|
+
description: `Search file contents within the Agentic File System (AFS)
|
|
8
|
+
- Searches for files containing specific text, keywords, or patterns
|
|
9
|
+
- Returns matching entries with their content and metadata
|
|
10
|
+
- Supports case-sensitive and case-insensitive search modes
|
|
11
|
+
- Use this tool when you need to find files by their content
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/", "/docs", "/memory")
|
|
15
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
16
|
+
- The query can be keywords, phrases, or text patterns to search for
|
|
17
|
+
- Use limit to control the number of results returned
|
|
18
|
+
- Search is case-insensitive by default; set caseSensitive to true for exact case matching`,
|
|
8
19
|
...options,
|
|
9
20
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
21
|
+
path: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe("Absolute AFS path to search in (e.g., '/', '/docs', '/memory'). Must start with '/'"),
|
|
24
|
+
query: z.string().describe("Text, keywords, or patterns to search for in file contents"),
|
|
12
25
|
options: z
|
|
13
26
|
.object({
|
|
14
|
-
limit: z
|
|
27
|
+
limit: z
|
|
28
|
+
.number()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Maximum number of results to return. Useful for limiting output size"),
|
|
15
31
|
caseSensitive: z
|
|
16
32
|
.boolean()
|
|
17
33
|
.optional()
|
|
18
|
-
.describe("
|
|
34
|
+
.describe("Set to true for case-sensitive matching. Default: false (case-insensitive)"),
|
|
19
35
|
})
|
|
20
36
|
.optional(),
|
|
21
37
|
}),
|
|
@@ -4,16 +4,30 @@ export class AFSWriteAgent extends AFSSkillBase {
|
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_write",
|
|
7
|
-
description:
|
|
7
|
+
description: `Write or create files in the Agentic File System (AFS)
|
|
8
|
+
- Creates a new file or overwrites an existing file with the provided content
|
|
9
|
+
- Supports append mode to add content to the end of existing files
|
|
10
|
+
- Use this tool when creating new files or completely replacing file contents
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/docs/new-file.md", "/memory/user/notes")
|
|
14
|
+
- This is NOT a local system file path - it operates within the AFS virtual file system
|
|
15
|
+
- By default, this tool overwrites the entire file content
|
|
16
|
+
- Use append mode to add content to the end of an existing file without replacing it
|
|
17
|
+
- For partial edits to existing files, prefer using afs_edit instead`,
|
|
8
18
|
...options,
|
|
9
19
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
20
|
+
path: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Absolute AFS path for the file to write (e.g., '/docs/new-file.md'). Must start with '/'"),
|
|
23
|
+
content: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe("The content to write to the file. In overwrite mode, this replaces the entire file"),
|
|
12
26
|
append: z
|
|
13
27
|
.boolean()
|
|
14
28
|
.optional()
|
|
15
29
|
.default(false)
|
|
16
|
-
.describe("
|
|
30
|
+
.describe("Set to true to append content to the end of an existing file. Default: false (overwrites entire file)"),
|
|
17
31
|
}),
|
|
18
32
|
outputSchema: z.object({
|
|
19
33
|
status: z.string(),
|