@aigne/core 1.71.0 → 1.72.0-beta.10
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 +158 -0
- package/lib/cjs/agents/agent.d.ts +42 -29
- package/lib/cjs/agents/agent.js +32 -11
- package/lib/cjs/agents/ai-agent.d.ts +63 -4
- package/lib/cjs/agents/ai-agent.js +148 -20
- package/lib/cjs/agents/chat-model.d.ts +162 -0
- package/lib/cjs/agents/chat-model.js +56 -5
- 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 +17 -2
- package/lib/cjs/agents/image-model.js +2 -0
- 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 +15 -0
- package/lib/cjs/agents/video-model.js +2 -0
- package/lib/cjs/aigne/usage.d.ts +5 -0
- package/lib/cjs/aigne/usage.js +6 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/loader/agent-yaml.d.ts +27 -64
- package/lib/cjs/loader/agent-yaml.js +22 -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 +16 -12
- package/lib/cjs/loader/index.js +46 -82
- package/lib/cjs/loader/schema.d.ts +21 -6
- package/lib/cjs/loader/schema.js +60 -1
- package/lib/cjs/memory/recorder.d.ts +4 -4
- package/lib/cjs/memory/retriever.d.ts +4 -4
- package/lib/cjs/prompt/agent-session.d.ts +135 -0
- package/lib/cjs/prompt/agent-session.js +889 -0
- package/lib/cjs/prompt/compact/compactor.d.ts +7 -0
- package/lib/cjs/prompt/compact/compactor.js +48 -0
- package/lib/cjs/prompt/compact/session-memory-extractor.d.ts +7 -0
- package/lib/cjs/prompt/compact/session-memory-extractor.js +139 -0
- package/lib/cjs/prompt/compact/types.d.ts +329 -0
- package/lib/cjs/prompt/compact/types.js +53 -0
- package/lib/cjs/prompt/compact/user-memory-extractor.d.ts +7 -0
- package/lib/cjs/prompt/compact/user-memory-extractor.js +120 -0
- package/lib/cjs/prompt/context/afs/history.d.ts +9 -0
- package/lib/cjs/prompt/context/afs/history.js +33 -0
- package/lib/cjs/prompt/context/afs/index.d.ts +20 -0
- package/lib/cjs/prompt/context/afs/index.js +54 -0
- package/lib/cjs/prompt/context/index.d.ts +31 -0
- package/lib/cjs/prompt/context/index.js +18 -0
- package/lib/cjs/prompt/prompt-builder.d.ts +11 -9
- package/lib/cjs/prompt/prompt-builder.js +81 -151
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.d.ts +18 -0
- package/lib/cjs/prompt/skills/afs/agent-skill/agent-skill.js +69 -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 +62 -0
- package/lib/cjs/prompt/skills/afs/base.d.ts +4 -0
- package/lib/cjs/prompt/skills/afs/base.js +8 -0
- package/lib/cjs/prompt/skills/afs/delete.d.ts +3 -2
- package/lib/cjs/prompt/skills/afs/delete.js +17 -5
- package/lib/cjs/prompt/skills/afs/edit.d.ts +9 -11
- package/lib/cjs/prompt/skills/afs/edit.js +89 -63
- package/lib/cjs/prompt/skills/afs/exec.d.ts +4 -3
- package/lib/cjs/prompt/skills/afs/exec.js +23 -7
- package/lib/cjs/prompt/skills/afs/index.js +4 -1
- package/lib/cjs/prompt/skills/afs/list.d.ts +4 -4
- package/lib/cjs/prompt/skills/afs/list.js +38 -55
- package/lib/cjs/prompt/skills/afs/read.d.ts +10 -5
- package/lib/cjs/prompt/skills/afs/read.js +66 -19
- package/lib/cjs/prompt/skills/afs/rename.d.ts +3 -2
- package/lib/cjs/prompt/skills/afs/rename.js +20 -6
- package/lib/cjs/prompt/skills/afs/search.d.ts +4 -3
- package/lib/cjs/prompt/skills/afs/search.js +24 -8
- package/lib/cjs/prompt/skills/afs/write.d.ts +3 -2
- package/lib/cjs/prompt/skills/afs/write.js +22 -8
- package/lib/cjs/prompt/template.d.ts +84 -9
- package/lib/cjs/prompt/template.js +46 -17
- package/lib/dts/agents/agent.d.ts +42 -29
- package/lib/dts/agents/ai-agent.d.ts +63 -4
- package/lib/dts/agents/chat-model.d.ts +162 -0
- package/lib/dts/agents/image-agent.d.ts +17 -1
- package/lib/dts/agents/image-model.d.ts +17 -2
- 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 +15 -0
- package/lib/dts/aigne/context.d.ts +2 -2
- package/lib/dts/aigne/usage.d.ts +5 -0
- package/lib/dts/index.d.ts +1 -0
- package/lib/dts/loader/agent-yaml.d.ts +27 -64
- package/lib/dts/loader/agents.d.ts +4 -0
- package/lib/dts/loader/index.d.ts +16 -12
- package/lib/dts/loader/schema.d.ts +21 -6
- package/lib/dts/memory/recorder.d.ts +4 -4
- package/lib/dts/memory/retriever.d.ts +4 -4
- package/lib/dts/prompt/agent-session.d.ts +135 -0
- package/lib/dts/prompt/compact/compactor.d.ts +7 -0
- package/lib/dts/prompt/compact/session-memory-extractor.d.ts +7 -0
- package/lib/dts/prompt/compact/types.d.ts +329 -0
- package/lib/dts/prompt/compact/user-memory-extractor.d.ts +7 -0
- package/lib/dts/prompt/context/afs/history.d.ts +9 -0
- package/lib/dts/prompt/context/afs/index.d.ts +20 -0
- package/lib/dts/prompt/context/index.d.ts +31 -0
- package/lib/dts/prompt/prompt-builder.d.ts +11 -9
- package/lib/dts/prompt/skills/afs/agent-skill/agent-skill.d.ts +18 -0
- package/lib/dts/prompt/skills/afs/agent-skill/skill-loader.d.ts +13 -0
- package/lib/dts/prompt/skills/afs/base.d.ts +4 -0
- package/lib/dts/prompt/skills/afs/delete.d.ts +3 -2
- package/lib/dts/prompt/skills/afs/edit.d.ts +9 -11
- package/lib/dts/prompt/skills/afs/exec.d.ts +4 -3
- package/lib/dts/prompt/skills/afs/list.d.ts +4 -4
- package/lib/dts/prompt/skills/afs/read.d.ts +10 -5
- package/lib/dts/prompt/skills/afs/rename.d.ts +3 -2
- package/lib/dts/prompt/skills/afs/search.d.ts +4 -3
- package/lib/dts/prompt/skills/afs/write.d.ts +3 -2
- package/lib/dts/prompt/template.d.ts +84 -9
- package/lib/esm/agents/agent.d.ts +42 -29
- package/lib/esm/agents/agent.js +32 -11
- package/lib/esm/agents/ai-agent.d.ts +63 -4
- package/lib/esm/agents/ai-agent.js +148 -20
- package/lib/esm/agents/chat-model.d.ts +162 -0
- package/lib/esm/agents/chat-model.js +55 -4
- 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 +17 -2
- package/lib/esm/agents/image-model.js +2 -0
- 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 +15 -0
- package/lib/esm/agents/video-model.js +2 -0
- package/lib/esm/aigne/context.d.ts +2 -2
- package/lib/esm/aigne/usage.d.ts +5 -0
- package/lib/esm/aigne/usage.js +6 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/loader/agent-yaml.d.ts +27 -64
- package/lib/esm/loader/agent-yaml.js +22 -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 +16 -12
- package/lib/esm/loader/index.js +47 -82
- package/lib/esm/loader/schema.d.ts +21 -6
- package/lib/esm/loader/schema.js +57 -0
- package/lib/esm/memory/recorder.d.ts +4 -4
- package/lib/esm/memory/retriever.d.ts +4 -4
- package/lib/esm/prompt/agent-session.d.ts +135 -0
- package/lib/esm/prompt/agent-session.js +849 -0
- package/lib/esm/prompt/compact/compactor.d.ts +7 -0
- package/lib/esm/prompt/compact/compactor.js +44 -0
- package/lib/esm/prompt/compact/session-memory-extractor.d.ts +7 -0
- package/lib/esm/prompt/compact/session-memory-extractor.js +135 -0
- package/lib/esm/prompt/compact/types.d.ts +329 -0
- package/lib/esm/prompt/compact/types.js +50 -0
- package/lib/esm/prompt/compact/user-memory-extractor.d.ts +7 -0
- package/lib/esm/prompt/compact/user-memory-extractor.js +116 -0
- package/lib/esm/prompt/context/afs/history.d.ts +9 -0
- package/lib/esm/prompt/context/afs/history.js +30 -0
- package/lib/esm/prompt/context/afs/index.d.ts +20 -0
- package/lib/esm/prompt/context/afs/index.js +51 -0
- package/lib/esm/prompt/context/index.d.ts +31 -0
- package/lib/esm/prompt/context/index.js +15 -0
- package/lib/esm/prompt/prompt-builder.d.ts +11 -9
- package/lib/esm/prompt/prompt-builder.js +80 -150
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.d.ts +18 -0
- package/lib/esm/prompt/skills/afs/agent-skill/agent-skill.js +65 -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 +54 -0
- package/lib/esm/prompt/skills/afs/base.d.ts +4 -0
- package/lib/esm/prompt/skills/afs/base.js +4 -0
- package/lib/esm/prompt/skills/afs/delete.d.ts +3 -2
- package/lib/esm/prompt/skills/afs/delete.js +17 -5
- package/lib/esm/prompt/skills/afs/edit.d.ts +9 -11
- package/lib/esm/prompt/skills/afs/edit.js +89 -63
- package/lib/esm/prompt/skills/afs/exec.d.ts +4 -3
- package/lib/esm/prompt/skills/afs/exec.js +23 -7
- package/lib/esm/prompt/skills/afs/index.js +4 -1
- package/lib/esm/prompt/skills/afs/list.d.ts +4 -4
- package/lib/esm/prompt/skills/afs/list.js +38 -55
- package/lib/esm/prompt/skills/afs/read.d.ts +10 -5
- package/lib/esm/prompt/skills/afs/read.js +66 -19
- package/lib/esm/prompt/skills/afs/rename.d.ts +3 -2
- package/lib/esm/prompt/skills/afs/rename.js +20 -6
- package/lib/esm/prompt/skills/afs/search.d.ts +4 -3
- package/lib/esm/prompt/skills/afs/search.js +24 -8
- package/lib/esm/prompt/skills/afs/write.d.ts +3 -2
- package/lib/esm/prompt/skills/afs/write.js +22 -8
- package/lib/esm/prompt/template.d.ts +84 -9
- package/lib/esm/prompt/template.js +46 -17
- package/package.json +6 -5
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
static formatOutput(output) {
|
|
9
|
+
if (!("result" in output) || typeof output.result !== "string") {
|
|
10
|
+
throw new Error("Invalid SkillToolOutput: missing 'result' field");
|
|
11
|
+
}
|
|
12
|
+
return output.result;
|
|
13
|
+
}
|
|
14
|
+
constructor(options) {
|
|
15
|
+
super({
|
|
16
|
+
name: "Skill",
|
|
17
|
+
taskTitle: "Invoke {{skill}}: {{args}}",
|
|
18
|
+
...options,
|
|
19
|
+
description: `\
|
|
20
|
+
Execute a skill within the main conversation
|
|
21
|
+
|
|
22
|
+
<skills_instructions>
|
|
23
|
+
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.
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
User: "run /commit" Assistant: [Calls Skill tool with skill: "commit"]
|
|
28
|
+
How to invoke:
|
|
29
|
+
|
|
30
|
+
Use this tool with the skill name and optional arguments
|
|
31
|
+
|
|
32
|
+
Important:
|
|
33
|
+
|
|
34
|
+
When a skill is relevant, you must invoke this tool IMMEDIATELY as your first action
|
|
35
|
+
NEVER just announce or mention a skill in your text response without actually calling this tool
|
|
36
|
+
This is a BLOCKING REQUIREMENT: invoke the relevant Skill tool BEFORE generating any other response about the task
|
|
37
|
+
Only use skills listed in <available_skills> below
|
|
38
|
+
Do not invoke a skill that is already running
|
|
39
|
+
Do not use this tool for built-in CLI commands (like /help, /clear, etc.)
|
|
40
|
+
</skills_instructions>
|
|
41
|
+
|
|
42
|
+
<available_skills>
|
|
43
|
+
${options.agentSkills.map((s) => `${s.name}: ${s.description}`).join("\n\n")}
|
|
44
|
+
</available_skills>
|
|
45
|
+
`,
|
|
46
|
+
inputSchema: skillToolInputSchema,
|
|
47
|
+
});
|
|
48
|
+
this.agentSkills = options.agentSkills;
|
|
49
|
+
}
|
|
50
|
+
agentSkills;
|
|
51
|
+
async process(input) {
|
|
52
|
+
const skill = this.agentSkills.find((s) => s.name === input.skill);
|
|
53
|
+
if (!skill)
|
|
54
|
+
throw new Error(`Skill not found: ${input.skill}`);
|
|
55
|
+
return {
|
|
56
|
+
result: `\
|
|
57
|
+
Base directory for this skill: ${skill.path}
|
|
58
|
+
|
|
59
|
+
${skill.content}
|
|
60
|
+
|
|
61
|
+
${input.args ? `ARGUMENTS: ${input.args ?? "None"}` : ""}
|
|
62
|
+
`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -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,54 @@
|
|
|
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
|
+
maxDepth: 10,
|
|
40
|
+
})).data;
|
|
41
|
+
for (const entry of data) {
|
|
42
|
+
const { data: file } = await afs.read(entry.path);
|
|
43
|
+
if (typeof file?.content !== "string")
|
|
44
|
+
continue;
|
|
45
|
+
const skill = parseSkill(file.content, nodejs.path.dirname(entry.path));
|
|
46
|
+
skills.push(skill);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!skills.length)
|
|
50
|
+
return;
|
|
51
|
+
return new AgentSkill({
|
|
52
|
+
agentSkills: skills,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
2
3
|
export interface AFSDeleteInput extends Message {
|
|
3
4
|
path: string;
|
|
4
5
|
recursive?: boolean;
|
|
@@ -12,7 +13,7 @@ export interface AFSDeleteOutput extends Message {
|
|
|
12
13
|
export interface AFSDeleteAgentOptions extends AgentOptions<AFSDeleteInput, AFSDeleteOutput> {
|
|
13
14
|
afs: NonNullable<AgentOptions<AFSDeleteInput, AFSDeleteOutput>["afs"]>;
|
|
14
15
|
}
|
|
15
|
-
export declare class AFSDeleteAgent extends
|
|
16
|
+
export declare class AFSDeleteAgent extends AFSSkillBase<AFSDeleteInput, AFSDeleteOutput> {
|
|
16
17
|
constructor(options: AFSDeleteAgentOptions);
|
|
17
18
|
process(input: AFSDeleteInput, _options: AgentInvokeOptions): Promise<AFSDeleteOutput>;
|
|
18
19
|
}
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
export class AFSDeleteAgent extends
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
3
|
+
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(),
|
|
@@ -1,26 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
start_line: number;
|
|
4
|
-
end_line: number;
|
|
5
|
-
replace?: string;
|
|
6
|
-
delete: boolean;
|
|
7
|
-
}
|
|
1
|
+
import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
8
3
|
export interface AFSEditInput extends Message {
|
|
9
4
|
path: string;
|
|
10
|
-
|
|
5
|
+
oldString: string;
|
|
6
|
+
newString: string;
|
|
7
|
+
replaceAll?: boolean;
|
|
11
8
|
}
|
|
12
9
|
export interface AFSEditOutput extends Message {
|
|
13
10
|
status: string;
|
|
14
11
|
tool: string;
|
|
15
12
|
path: string;
|
|
16
13
|
message: string;
|
|
17
|
-
|
|
14
|
+
snippet: string;
|
|
18
15
|
}
|
|
19
16
|
export interface AFSEditAgentOptions extends AgentOptions<AFSEditInput, AFSEditOutput> {
|
|
20
17
|
afs: NonNullable<AgentOptions<AFSEditInput, AFSEditOutput>["afs"]>;
|
|
21
18
|
}
|
|
22
|
-
export declare class AFSEditAgent extends
|
|
19
|
+
export declare class AFSEditAgent extends AFSSkillBase<AFSEditInput, AFSEditOutput> {
|
|
23
20
|
constructor(options: AFSEditAgentOptions);
|
|
24
21
|
process(input: AFSEditInput, _options: AgentInvokeOptions): Promise<AFSEditOutput>;
|
|
25
|
-
|
|
22
|
+
private countOccurrences;
|
|
23
|
+
private extractSnippet;
|
|
26
24
|
}
|
|
@@ -1,94 +1,120 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
3
|
+
const CONTEXT_LINES = 4; // Number of lines to show before and after the edit
|
|
4
|
+
export class AFSEditAgent extends AFSSkillBase {
|
|
4
5
|
constructor(options) {
|
|
5
6
|
super({
|
|
6
7
|
name: "afs_edit",
|
|
7
|
-
description:
|
|
8
|
+
description: `Performs exact string replacements in files within the Agentic File System (AFS).
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
- You must use afs_read at least once before editing to understand the file content
|
|
12
|
+
- The path must be an absolute AFS path starting with "/" (e.g., "/docs/readme.md")
|
|
13
|
+
- Preserve exact indentation (tabs/spaces) as it appears in the file
|
|
14
|
+
- The edit will FAIL if oldString is not found in the file
|
|
15
|
+
- The edit will FAIL if oldString appears multiple times (unless replaceAll is true)
|
|
16
|
+
- Use replaceAll to replace/rename strings across the entire file`,
|
|
8
17
|
...options,
|
|
9
18
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
12
|
-
.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
19
|
+
path: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe("Absolute AFS path to the file to edit (e.g., '/docs/readme.md'). Must start with '/'"),
|
|
22
|
+
oldString: z
|
|
23
|
+
.string()
|
|
24
|
+
.describe("The exact text to replace. Must match file content exactly including whitespace"),
|
|
25
|
+
newString: z
|
|
26
|
+
.string()
|
|
27
|
+
.describe("The text to replace it with (must be different from oldString)"),
|
|
28
|
+
replaceAll: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.optional()
|
|
31
|
+
.default(false)
|
|
32
|
+
.describe("Replace all occurrences of oldString (default: false)"),
|
|
20
33
|
}),
|
|
21
34
|
outputSchema: z.object({
|
|
22
35
|
status: z.string(),
|
|
23
36
|
tool: z.string(),
|
|
24
37
|
path: z.string(),
|
|
25
38
|
message: z.string(),
|
|
26
|
-
|
|
39
|
+
snippet: z.string(),
|
|
27
40
|
}),
|
|
28
41
|
});
|
|
29
42
|
}
|
|
30
43
|
async process(input, _options) {
|
|
31
44
|
if (!this.afs)
|
|
32
45
|
throw new Error("AFS is not configured for this agent.");
|
|
33
|
-
|
|
34
|
-
|
|
46
|
+
const { path, oldString, newString, replaceAll = false } = input;
|
|
47
|
+
if (oldString === newString) {
|
|
48
|
+
throw new Error("oldString and newString must be different");
|
|
35
49
|
}
|
|
36
|
-
const readResult = await this.afs.read(
|
|
37
|
-
if (!readResult.
|
|
38
|
-
throw new Error(`Cannot read file content from: ${
|
|
50
|
+
const readResult = await this.afs.read(path);
|
|
51
|
+
if (!readResult.data?.content || typeof readResult.data.content !== "string") {
|
|
52
|
+
throw new Error(`Cannot read file content from: ${path}`);
|
|
39
53
|
}
|
|
40
|
-
const originalContent = readResult.
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
const originalContent = readResult.data.content;
|
|
55
|
+
// Check if oldString exists in the file
|
|
56
|
+
const occurrences = this.countOccurrences(originalContent, oldString);
|
|
57
|
+
if (occurrences === 0) {
|
|
58
|
+
throw new Error(`oldString not found in file: ${path}`);
|
|
59
|
+
}
|
|
60
|
+
if (occurrences > 1 && !replaceAll) {
|
|
61
|
+
throw new Error(`oldString appears ${occurrences} times in file. Use replaceAll=true to replace all occurrences, or provide more context to make oldString unique.`);
|
|
62
|
+
}
|
|
63
|
+
// Find the position of the first occurrence for snippet extraction
|
|
64
|
+
const firstOccurrenceIndex = originalContent.indexOf(oldString);
|
|
65
|
+
// Perform the replacement
|
|
66
|
+
const updatedContent = replaceAll
|
|
67
|
+
? originalContent.split(oldString).join(newString)
|
|
68
|
+
: originalContent.replace(oldString, newString);
|
|
69
|
+
await this.afs.write(path, {
|
|
43
70
|
content: updatedContent,
|
|
44
71
|
});
|
|
72
|
+
// Generate snippet around the edit location
|
|
73
|
+
const snippet = this.extractSnippet(updatedContent, firstOccurrenceIndex, newString.length);
|
|
74
|
+
const replacementCount = replaceAll ? occurrences : 1;
|
|
45
75
|
return {
|
|
46
76
|
status: "success",
|
|
47
77
|
tool: "afs_edit",
|
|
48
|
-
path
|
|
49
|
-
message: `
|
|
50
|
-
|
|
78
|
+
path,
|
|
79
|
+
message: `Replaced ${replacementCount} occurrence${replacementCount > 1 ? "s" : ""} in ${path}`,
|
|
80
|
+
snippet,
|
|
51
81
|
};
|
|
52
82
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const replaceLines = patch.replace ? patch.replace.split("\n") : [];
|
|
73
|
-
lines.splice(start, deleteCount, ...replaceLines);
|
|
74
|
-
delta = replaceLines.length - deleteCount;
|
|
75
|
-
}
|
|
76
|
-
// Update subsequent patches' line numbers
|
|
77
|
-
// For exclusive-end semantics [start, end), we adjust patches that start >= current patch's start_line
|
|
78
|
-
// after the current patch has been applied
|
|
79
|
-
if (delta !== 0) {
|
|
80
|
-
for (let j = i + 1; j < sorted.length; j++) {
|
|
81
|
-
const next = sorted[j];
|
|
82
|
-
if (!next)
|
|
83
|
-
continue;
|
|
84
|
-
// Adjust patches that start at or after the current patch's end line
|
|
85
|
-
if (next.start_line >= patch.end_line) {
|
|
86
|
-
next.start_line += delta;
|
|
87
|
-
next.end_line += delta;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
83
|
+
countOccurrences(text, search) {
|
|
84
|
+
let count = 0;
|
|
85
|
+
let position = text.indexOf(search);
|
|
86
|
+
while (position !== -1) {
|
|
87
|
+
count++;
|
|
88
|
+
position = text.indexOf(search, position + search.length);
|
|
89
|
+
}
|
|
90
|
+
return count;
|
|
91
|
+
}
|
|
92
|
+
extractSnippet(content, editStartIndex, newStringLength) {
|
|
93
|
+
const lines = content.split("\n");
|
|
94
|
+
// Find the line number where the edit starts
|
|
95
|
+
let charCount = 0;
|
|
96
|
+
let editStartLine = 0;
|
|
97
|
+
for (let i = 0; i < lines.length; i++) {
|
|
98
|
+
const lineLength = (lines[i]?.length ?? 0) + 1; // +1 for newline
|
|
99
|
+
if (charCount + lineLength > editStartIndex) {
|
|
100
|
+
editStartLine = i;
|
|
101
|
+
break;
|
|
90
102
|
}
|
|
103
|
+
charCount += lineLength;
|
|
91
104
|
}
|
|
92
|
-
|
|
105
|
+
// Calculate how many lines the new content spans
|
|
106
|
+
const newContentLines = content
|
|
107
|
+
.substring(editStartIndex, editStartIndex + newStringLength)
|
|
108
|
+
.split("\n").length;
|
|
109
|
+
const editEndLine = editStartLine + newContentLines - 1;
|
|
110
|
+
// Extract lines with context
|
|
111
|
+
const startLine = Math.max(0, editStartLine - CONTEXT_LINES);
|
|
112
|
+
const endLine = Math.min(lines.length - 1, editEndLine + CONTEXT_LINES);
|
|
113
|
+
// Format with line numbers (1-based)
|
|
114
|
+
const snippetLines = lines.slice(startLine, endLine + 1).map((line, idx) => {
|
|
115
|
+
const lineNum = startLine + idx + 1;
|
|
116
|
+
return `${String(lineNum).padStart(4)}| ${line}`;
|
|
117
|
+
});
|
|
118
|
+
return snippetLines.join("\n");
|
|
93
119
|
}
|
|
94
120
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
2
3
|
export interface AFSExecInput extends Message {
|
|
3
4
|
path: string;
|
|
4
5
|
args: string;
|
|
5
6
|
}
|
|
6
7
|
export interface AFSExecOutput extends Message {
|
|
7
|
-
|
|
8
|
+
data: Record<string, any>;
|
|
8
9
|
}
|
|
9
10
|
export interface AFSExecAgentOptions extends AgentOptions<AFSExecInput, AFSExecOutput> {
|
|
10
11
|
afs: NonNullable<AgentOptions<AFSExecInput, AFSExecOutput>["afs"]>;
|
|
11
12
|
}
|
|
12
|
-
export declare class AFSExecAgent extends
|
|
13
|
+
export declare class AFSExecAgent extends AFSSkillBase<AFSExecInput, AFSExecOutput> {
|
|
13
14
|
constructor(options: AFSExecAgentOptions);
|
|
14
15
|
process(input: AFSExecInput, options: AgentInvokeOptions): Promise<AFSExecOutput>;
|
|
15
16
|
}
|
|
@@ -1,23 +1,39 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
3
|
-
export class AFSExecAgent extends
|
|
2
|
+
import { AFSSkillBase } from "./base.js";
|
|
3
|
+
export class AFSExecAgent extends AFSSkillBase {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
super({
|
|
6
6
|
name: "afs_exec",
|
|
7
|
-
description:
|
|
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`,
|
|
8
18
|
...options,
|
|
9
19
|
inputSchema: z.object({
|
|
10
|
-
path: z
|
|
11
|
-
|
|
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"}\')'),
|
|
12
26
|
}),
|
|
13
27
|
outputSchema: z.object({
|
|
14
|
-
|
|
28
|
+
data: z.record(z.any()),
|
|
15
29
|
}),
|
|
16
30
|
});
|
|
17
31
|
}
|
|
18
32
|
async process(input, options) {
|
|
19
33
|
if (!this.afs)
|
|
20
34
|
throw new Error("AFS is not configured for this agent.");
|
|
21
|
-
return
|
|
35
|
+
return {
|
|
36
|
+
...(await this.afs.exec(input.path, JSON.parse(input.args), options)),
|
|
37
|
+
};
|
|
22
38
|
}
|
|
23
39
|
}
|
|
@@ -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
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AFSListOptions } from "@aigne/afs";
|
|
2
|
-
import {
|
|
2
|
+
import type { AgentInvokeOptions, AgentOptions, Message } from "../../../agents/agent.js";
|
|
3
|
+
import { AFSSkillBase } from "./base.js";
|
|
3
4
|
export interface AFSListInput extends Message {
|
|
4
5
|
path: string;
|
|
5
6
|
options?: AFSListOptions;
|
|
@@ -10,13 +11,12 @@ export interface AFSListOutput extends Message {
|
|
|
10
11
|
path: string;
|
|
11
12
|
options?: AFSListOptions;
|
|
12
13
|
message?: string;
|
|
13
|
-
|
|
14
|
+
data?: unknown;
|
|
14
15
|
}
|
|
15
16
|
export interface AFSListAgentOptions extends AgentOptions<AFSListInput, AFSListOutput> {
|
|
16
17
|
afs: NonNullable<AgentOptions<AFSListInput, AFSListOutput>["afs"]>;
|
|
17
18
|
}
|
|
18
|
-
export declare class AFSListAgent extends
|
|
19
|
+
export declare class AFSListAgent extends AFSSkillBase<AFSListInput, AFSListOutput> {
|
|
19
20
|
constructor(options: AFSListAgentOptions);
|
|
20
21
|
process(input: AFSListInput, _options: AgentInvokeOptions): Promise<AFSListOutput>;
|
|
21
|
-
private buildTreeView;
|
|
22
22
|
}
|