xiaozuoassistant 0.2.19 → 0.2.21
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/README.md +119 -119
- package/bin/cli.js +896 -896
- package/config.json +41 -41
- package/dist/client/assets/browser-ponyfill-Bcpejndl.js +2 -0
- package/dist/client/assets/index-BfvHy-SS.js +201 -0
- package/dist/client/assets/index-u0lXmgyZ.css +1 -0
- package/dist/client/favicon.svg +4 -0
- package/dist/client/index.html +14 -0
- package/dist/client/locales/en/translation.json +110 -0
- package/dist/client/locales/zh/translation.json +112 -0
- package/dist/server/agents/office.js +23 -0
- package/dist/server/app.js +50 -0
- package/dist/server/channels/base-channel.js +23 -0
- package/dist/server/channels/create-channels.js +18 -0
- package/dist/server/channels/dingtalk.js +83 -0
- package/dist/server/channels/feishu.js +139 -0
- package/dist/server/channels/telegram.js +53 -0
- package/dist/server/channels/terminal.js +49 -0
- package/dist/server/channels/web.js +66 -0
- package/dist/server/channels/wechat.js +107 -0
- package/dist/server/config/loader.js +111 -0
- package/dist/server/config/paths.js +24 -0
- package/dist/server/config/prompts.js +12 -0
- package/dist/server/core/agents/manager.js +27 -0
- package/dist/server/core/agents/runtime.js +92 -0
- package/dist/server/core/brain.js +255 -0
- package/dist/server/core/event-bus.js +24 -0
- package/dist/server/core/logger.js +71 -0
- package/dist/server/core/memories/manager.js +238 -0
- package/dist/server/core/memories/short-term.js +512 -0
- package/dist/server/core/memories/structured.js +357 -0
- package/dist/server/core/memories/vector.js +137 -0
- package/dist/server/core/memory.js +2 -0
- package/dist/server/core/plugin-manager.js +128 -0
- package/dist/server/core/plugin.js +1 -0
- package/dist/server/core/scheduler.js +85 -0
- package/dist/server/core/task-queue.js +104 -0
- package/dist/server/core/types.js +1 -0
- package/dist/server/index.js +878 -0
- package/dist/server/llm/openai.js +23 -0
- package/dist/server/plugins/core-skills/src/create-agent.js +58 -0
- package/dist/server/plugins/core-skills/src/delegate.js +39 -0
- package/dist/server/plugins/core-skills/src/file-system.js +142 -0
- package/dist/server/plugins/core-skills/src/index.js +26 -0
- package/dist/server/plugins/core-skills/src/list-agents.js +24 -0
- package/dist/server/plugins/core-skills/src/search.js +31 -0
- package/dist/server/plugins/core-skills/src/system-time.js +27 -0
- package/dist/server/plugins/office-skills/src/index.js +19 -0
- package/dist/server/plugins/office-skills/src/office-excel.js +84 -0
- package/dist/server/plugins/office-skills/src/office-ppt.js +58 -0
- package/dist/server/plugins/office-skills/src/office-word.js +90 -0
- package/dist/server/routes/auth.js +28 -0
- package/dist/server/server/create-http.js +22 -0
- package/dist/server/server.js +29 -0
- package/dist/server/skills/base-skill.js +20 -0
- package/dist/server/skills/registry.js +52 -0
- package/package.json +116 -116
- package/public/favicon.svg +4 -4
- package/public/locales/en/translation.json +110 -110
- package/public/locales/zh/translation.json +112 -112
- package/scripts/init-app-home.cjs +43 -43
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
export function resolveBaseURL(config) {
|
|
3
|
+
switch (config.provider) {
|
|
4
|
+
case 'deepseek':
|
|
5
|
+
return 'https://api.deepseek.com';
|
|
6
|
+
case 'minimax':
|
|
7
|
+
return 'https://api.minimax.chat/v1';
|
|
8
|
+
case 'doubao':
|
|
9
|
+
return 'https://ark.cn-beijing.volces.com/api/v3';
|
|
10
|
+
case 'qwen':
|
|
11
|
+
return 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1';
|
|
12
|
+
case 'custom':
|
|
13
|
+
case 'openai':
|
|
14
|
+
default:
|
|
15
|
+
return config.baseURL;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function createOpenAIClient(config) {
|
|
19
|
+
return new OpenAI({
|
|
20
|
+
apiKey: config.apiKey || '',
|
|
21
|
+
baseURL: resolveBaseURL(config)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import { AgentRuntime } from '../../../core/agents/runtime.js';
|
|
3
|
+
import { agentManager } from '../../../core/agents/manager.js';
|
|
4
|
+
import { skillRegistry } from '../../../skills/registry.js';
|
|
5
|
+
export class CreateAgentSkill extends BaseSkill {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'create_agent';
|
|
9
|
+
this.description = 'Create a new specialized agent dynamically. Use this when the user wants to define a new role or expert.';
|
|
10
|
+
this.parameters = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The unique name of the agent (e.g., "coding_expert", "translator")'
|
|
16
|
+
},
|
|
17
|
+
description: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'A brief description of what this agent does'
|
|
20
|
+
},
|
|
21
|
+
systemPrompt: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The system instructions/persona for the agent'
|
|
24
|
+
},
|
|
25
|
+
skills: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: {
|
|
28
|
+
type: 'string'
|
|
29
|
+
},
|
|
30
|
+
description: 'List of existing skill names to assign to this agent (e.g., ["search", "read_file"])'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: ['name', 'description', 'systemPrompt']
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async execute(args, _ctx) {
|
|
37
|
+
if (agentManager.getAgent(args.name)) {
|
|
38
|
+
return { error: `Agent '${args.name}' already exists.` };
|
|
39
|
+
}
|
|
40
|
+
const assignedSkills = [];
|
|
41
|
+
if (args.skills) {
|
|
42
|
+
for (const skillName of args.skills) {
|
|
43
|
+
const skill = skillRegistry.getSkill(skillName);
|
|
44
|
+
if (skill) {
|
|
45
|
+
assignedSkills.push(skill);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const newAgent = new AgentRuntime({
|
|
50
|
+
name: args.name,
|
|
51
|
+
description: args.description,
|
|
52
|
+
systemPrompt: args.systemPrompt,
|
|
53
|
+
skills: assignedSkills
|
|
54
|
+
});
|
|
55
|
+
agentManager.registerAgent(newAgent);
|
|
56
|
+
return { success: true, message: `Agent '${args.name}' created successfully.` };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import { agentManager } from '../../../core/agents/manager.js';
|
|
3
|
+
export class DelegateSkill extends BaseSkill {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.name = 'delegate_task';
|
|
7
|
+
this.description = 'Delegate a complex task to a specialized agent. Use this when the user asks for something that requires specific expertise (e.g., "office_agent" for documents).';
|
|
8
|
+
this.parameters = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
agentName: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
description: 'The name of the agent to delegate to (e.g., "office_agent")',
|
|
14
|
+
enum: ['office_agent'] // Dynamically updated ideally, but hardcoded for now or fetch from manager
|
|
15
|
+
},
|
|
16
|
+
task: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'The detailed task description for the agent'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
required: ['agentName', 'task']
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async execute(args, _ctx) {
|
|
25
|
+
const agent = agentManager.getAgent(args.agentName);
|
|
26
|
+
if (!agent) {
|
|
27
|
+
return { error: `Agent '${args.agentName}' not found. Available agents: ${agentManager.getAllAgents().map(a => a.name).join(', ')}` };
|
|
28
|
+
}
|
|
29
|
+
console.log(`[DelegateSkill] Delegating to ${args.agentName}: ${args.task}`);
|
|
30
|
+
try {
|
|
31
|
+
// We start a fresh conversation for the sub-agent for now (stateless delegation)
|
|
32
|
+
const response = await agent.process([], args.task);
|
|
33
|
+
return { result: response, from: args.agentName };
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
return { error: `Delegation failed: ${e.message}` };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { resolvePathWithinWorkspace, resolveSessionWorkspace } from '../../../config/paths.js';
|
|
5
|
+
export class ListDirectorySkill extends BaseSkill {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'fs_list_directory';
|
|
9
|
+
this.description = 'List files and directories in a given path';
|
|
10
|
+
this.parameters = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
path: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Absolute path, or relative to the current session workspace. Defaults to the session workspace.'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
required: []
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async execute(params, ctx) {
|
|
22
|
+
const workspace = resolveSessionWorkspace(ctx);
|
|
23
|
+
const dirPath = params.path ? resolvePathWithinWorkspace(workspace, String(params.path)) : workspace;
|
|
24
|
+
try {
|
|
25
|
+
const files = await fs.readdir(dirPath, { withFileTypes: true });
|
|
26
|
+
return files.map(file => ({
|
|
27
|
+
name: file.name,
|
|
28
|
+
type: file.isDirectory() ? 'directory' : 'file'
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return `Error listing directory: ${error.message}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class ReadFileSkill extends BaseSkill {
|
|
37
|
+
constructor() {
|
|
38
|
+
super(...arguments);
|
|
39
|
+
this.name = 'fs_read_file';
|
|
40
|
+
this.description = 'Read the content of a file';
|
|
41
|
+
this.parameters = {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
path: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
description: 'Absolute path, or relative to the current session workspace.'
|
|
47
|
+
},
|
|
48
|
+
encoding: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'The encoding to use (default: utf-8)',
|
|
51
|
+
enum: ['utf-8', 'base64']
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
required: ['path']
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async execute(params, ctx) {
|
|
58
|
+
const workspace = resolveSessionWorkspace(ctx);
|
|
59
|
+
const filePath = resolvePathWithinWorkspace(workspace, String(params.path));
|
|
60
|
+
const encoding = params.encoding || 'utf-8';
|
|
61
|
+
try {
|
|
62
|
+
const content = await fs.readFile(filePath, { encoding: encoding });
|
|
63
|
+
return content;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return `Error reading file: ${error.message}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class WriteFileSkill extends BaseSkill {
|
|
71
|
+
constructor() {
|
|
72
|
+
super(...arguments);
|
|
73
|
+
this.name = 'fs_write_file';
|
|
74
|
+
this.description = 'Write content to a file (overwrites existing file)';
|
|
75
|
+
this.parameters = {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
path: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'Absolute path, or relative to the current session workspace.'
|
|
81
|
+
},
|
|
82
|
+
content: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'The content to write to the file'
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
required: ['path', 'content']
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
async execute(params, ctx) {
|
|
91
|
+
const workspace = resolveSessionWorkspace(ctx);
|
|
92
|
+
const filePath = resolvePathWithinWorkspace(workspace, String(params.path));
|
|
93
|
+
try {
|
|
94
|
+
// Ensure directory exists
|
|
95
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
96
|
+
await fs.writeFile(filePath, params.content, 'utf-8');
|
|
97
|
+
return `Successfully wrote to ${filePath}`;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return `Error writing file: ${error.message}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export class DeleteFileSkill extends BaseSkill {
|
|
105
|
+
constructor() {
|
|
106
|
+
super(...arguments);
|
|
107
|
+
this.name = 'fs_delete_file';
|
|
108
|
+
this.description = 'Delete a file or directory';
|
|
109
|
+
this.parameters = {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {
|
|
112
|
+
path: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'Absolute path, or relative to the current session workspace.'
|
|
115
|
+
},
|
|
116
|
+
recursive: {
|
|
117
|
+
type: 'boolean',
|
|
118
|
+
description: 'Whether to delete recursively (for directories). Default: false'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
required: ['path']
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async execute(params, ctx) {
|
|
125
|
+
const workspace = resolveSessionWorkspace(ctx);
|
|
126
|
+
const filePath = resolvePathWithinWorkspace(workspace, String(params.path));
|
|
127
|
+
const recursive = params.recursive || false;
|
|
128
|
+
try {
|
|
129
|
+
const stats = await fs.stat(filePath);
|
|
130
|
+
if (stats.isDirectory()) {
|
|
131
|
+
await fs.rm(filePath, { recursive, force: true });
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
await fs.unlink(filePath);
|
|
135
|
+
}
|
|
136
|
+
return `Successfully deleted ${filePath}`;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return `Error deleting file: ${error.message}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ListDirectorySkill, ReadFileSkill, WriteFileSkill, DeleteFileSkill } from './file-system.js';
|
|
2
|
+
import { SearchSkill } from './search.js';
|
|
3
|
+
import { SystemTimeSkill } from './system-time.js';
|
|
4
|
+
import { CreateAgentSkill } from './create-agent.js';
|
|
5
|
+
import { DelegateSkill } from './delegate.js';
|
|
6
|
+
import { ListAgentsSkill } from './list-agents.js';
|
|
7
|
+
const plugin = {
|
|
8
|
+
metadata: {
|
|
9
|
+
name: 'core-skills',
|
|
10
|
+
version: '1.0.0',
|
|
11
|
+
description: 'Core system skills for XiaoZuoClaw',
|
|
12
|
+
author: 'XiaoZuoClaw Team'
|
|
13
|
+
},
|
|
14
|
+
onLoad: (context) => {
|
|
15
|
+
context.registerSkill(new ListDirectorySkill());
|
|
16
|
+
context.registerSkill(new ReadFileSkill());
|
|
17
|
+
context.registerSkill(new WriteFileSkill());
|
|
18
|
+
context.registerSkill(new DeleteFileSkill());
|
|
19
|
+
context.registerSkill(new SearchSkill());
|
|
20
|
+
context.registerSkill(new SystemTimeSkill());
|
|
21
|
+
context.registerSkill(new CreateAgentSkill());
|
|
22
|
+
context.registerSkill(new DelegateSkill());
|
|
23
|
+
context.registerSkill(new ListAgentsSkill());
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export default plugin;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import { agentManager } from '../../../core/agents/manager.js';
|
|
3
|
+
export class ListAgentsSkill extends BaseSkill {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.name = 'list_agents';
|
|
7
|
+
this.description = 'List all available agents and their descriptions.';
|
|
8
|
+
this.parameters = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {},
|
|
11
|
+
required: []
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async execute(_params, _ctx) {
|
|
15
|
+
const agents = agentManager.getAllAgents();
|
|
16
|
+
return {
|
|
17
|
+
agents: agents.map(a => ({
|
|
18
|
+
name: a.name,
|
|
19
|
+
description: a.description,
|
|
20
|
+
tools: a.getToolsDefinition().map(t => t.function.name)
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
export class SearchSkill extends BaseSkill {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.name = 'web_search';
|
|
6
|
+
this.description = 'Search the web for information';
|
|
7
|
+
this.parameters = {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
query: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'The search query'
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
required: ['query']
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async execute(params, _ctx) {
|
|
19
|
+
const { query } = params;
|
|
20
|
+
// 这里可以集成真实的搜索 API,如 Google Search API 或 SerpApi
|
|
21
|
+
// 为了简化,我们返回一个模拟结果
|
|
22
|
+
return {
|
|
23
|
+
results: [
|
|
24
|
+
{
|
|
25
|
+
title: `Result for ${query}`,
|
|
26
|
+
snippet: `This is a simulated search result for "${query}". In a real implementation, this would call a search engine API.`
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
export class SystemTimeSkill extends BaseSkill {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.name = 'get_system_time';
|
|
6
|
+
this.description = 'Get the current system time';
|
|
7
|
+
this.parameters = {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
format: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'The format of the time (e.g., "iso", "locale")',
|
|
13
|
+
enum: ['iso', 'locale']
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
required: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async execute(params, _ctx) {
|
|
20
|
+
const format = params.format || 'iso';
|
|
21
|
+
const now = new Date();
|
|
22
|
+
if (format === 'locale') {
|
|
23
|
+
return now.toLocaleString();
|
|
24
|
+
}
|
|
25
|
+
return now.toISOString();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ReadWordSkill, CreateWordSkill } from './office-word.js';
|
|
2
|
+
import { ReadExcelSkill, CreateExcelSkill } from './office-excel.js';
|
|
3
|
+
import { CreatePptxSkill } from './office-ppt.js';
|
|
4
|
+
const plugin = {
|
|
5
|
+
metadata: {
|
|
6
|
+
name: 'office-skills',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
description: 'Microsoft Office integration skills (Word, Excel, PowerPoint)',
|
|
9
|
+
author: 'XiaoZuoClaw Team'
|
|
10
|
+
},
|
|
11
|
+
onLoad: (context) => {
|
|
12
|
+
context.registerSkill(new ReadWordSkill());
|
|
13
|
+
context.registerSkill(new CreateWordSkill());
|
|
14
|
+
context.registerSkill(new ReadExcelSkill());
|
|
15
|
+
context.registerSkill(new CreateExcelSkill());
|
|
16
|
+
context.registerSkill(new CreatePptxSkill());
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export default plugin;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import xlsx from 'xlsx';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
export class ReadExcelSkill extends BaseSkill {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.name = 'read_excel_file';
|
|
8
|
+
this.description = 'Read data from a Microsoft Excel (.xlsx) file as JSON';
|
|
9
|
+
this.parameters = {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'The absolute path to the .xlsx file'
|
|
15
|
+
},
|
|
16
|
+
sheet_name: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
description: 'Optional: specific sheet name to read. If omitted, reads the first sheet.'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
required: ['file_path']
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async execute(args, _ctx) {
|
|
25
|
+
try {
|
|
26
|
+
if (!fs.existsSync(args.file_path)) {
|
|
27
|
+
return { error: `File not found: ${args.file_path}` };
|
|
28
|
+
}
|
|
29
|
+
const workbook = xlsx.readFile(args.file_path);
|
|
30
|
+
const sheetName = args.sheet_name || workbook.SheetNames[0];
|
|
31
|
+
if (!workbook.Sheets[sheetName]) {
|
|
32
|
+
return { error: `Sheet "${sheetName}" not found. Available sheets: ${workbook.SheetNames.join(', ')}` };
|
|
33
|
+
}
|
|
34
|
+
const sheet = workbook.Sheets[sheetName];
|
|
35
|
+
const data = xlsx.utils.sheet_to_json(sheet);
|
|
36
|
+
return {
|
|
37
|
+
sheet: sheetName,
|
|
38
|
+
data: data
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return { error: `Failed to read Excel file: ${error.message}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export class CreateExcelSkill extends BaseSkill {
|
|
47
|
+
constructor() {
|
|
48
|
+
super(...arguments);
|
|
49
|
+
this.name = 'create_excel_file';
|
|
50
|
+
this.description = 'Create a new Microsoft Excel (.xlsx) file with data';
|
|
51
|
+
this.parameters = {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
file_path: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'The absolute path where the .xlsx file should be saved'
|
|
57
|
+
},
|
|
58
|
+
data: {
|
|
59
|
+
type: 'array',
|
|
60
|
+
items: { type: 'object' },
|
|
61
|
+
description: 'Array of objects representing rows of data'
|
|
62
|
+
},
|
|
63
|
+
sheet_name: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
description: 'Optional: name of the sheet. Defaults to "Sheet1".'
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
required: ['file_path', 'data']
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async execute(args, _ctx) {
|
|
72
|
+
try {
|
|
73
|
+
const workbook = xlsx.utils.book_new();
|
|
74
|
+
const sheet = xlsx.utils.json_to_sheet(args.data);
|
|
75
|
+
const sheetName = args.sheet_name || 'Sheet1';
|
|
76
|
+
xlsx.utils.book_append_sheet(workbook, sheet, sheetName);
|
|
77
|
+
xlsx.writeFile(workbook, args.file_path);
|
|
78
|
+
return { success: true, message: `Excel file created at ${args.file_path}` };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return { error: `Failed to create Excel file: ${error.message}` };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import pptxgen from 'pptxgenjs';
|
|
3
|
+
export class CreatePptxSkill extends BaseSkill {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.name = 'create_pptx_file';
|
|
7
|
+
this.description = 'Create a new Microsoft PowerPoint (.pptx) file with slides';
|
|
8
|
+
this.parameters = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
file_path: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
description: 'The absolute path where the .pptx file should be saved'
|
|
14
|
+
},
|
|
15
|
+
slides: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
items: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
title: { type: 'string' },
|
|
21
|
+
content: { type: 'string' } // Simple text content for now
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
description: 'Array of slide objects with title and content'
|
|
25
|
+
},
|
|
26
|
+
author: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Optional author name'
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
required: ['file_path', 'slides']
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async execute(args, _ctx) {
|
|
35
|
+
try {
|
|
36
|
+
// Handle different import styles (ESM/CJS interop)
|
|
37
|
+
const PptxGenJS = pptxgen.default || pptxgen;
|
|
38
|
+
const pres = new PptxGenJS();
|
|
39
|
+
if (args.author) {
|
|
40
|
+
pres.author = args.author;
|
|
41
|
+
}
|
|
42
|
+
for (const slideData of args.slides) {
|
|
43
|
+
const slide = pres.addSlide();
|
|
44
|
+
if (slideData.title) {
|
|
45
|
+
slide.addText(slideData.title, { x: 1, y: 1, w: '80%', h: 1, fontSize: 24, align: 'center', bold: true });
|
|
46
|
+
}
|
|
47
|
+
if (slideData.content) {
|
|
48
|
+
slide.addText(slideData.content, { x: 1, y: 2.5, w: '80%', h: 3, fontSize: 18 });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
await pres.writeFile({ fileName: args.file_path });
|
|
52
|
+
return { success: true, message: `PowerPoint file created at ${args.file_path}` };
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return { error: `Failed to create PowerPoint file: ${error.message}` };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
|
+
import mammoth from 'mammoth';
|
|
3
|
+
import officegen from 'officegen';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
export class ReadWordSkill extends BaseSkill {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'read_word_file';
|
|
9
|
+
this.description = 'Read text content from a Microsoft Word (.docx) file';
|
|
10
|
+
this.parameters = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
file_path: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The absolute path to the .docx file'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
required: ['file_path']
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async execute(args, _ctx) {
|
|
22
|
+
try {
|
|
23
|
+
if (!fs.existsSync(args.file_path)) {
|
|
24
|
+
return { error: `File not found: ${args.file_path}` };
|
|
25
|
+
}
|
|
26
|
+
const result = await mammoth.extractRawText({ path: args.file_path });
|
|
27
|
+
return { content: result.value };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return { error: `Failed to read Word file: ${error.message}` };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class CreateWordSkill extends BaseSkill {
|
|
35
|
+
constructor() {
|
|
36
|
+
super(...arguments);
|
|
37
|
+
this.name = 'create_word_file';
|
|
38
|
+
this.description = 'Create a new Microsoft Word (.docx) file with text content';
|
|
39
|
+
this.parameters = {
|
|
40
|
+
type: 'object',
|
|
41
|
+
properties: {
|
|
42
|
+
file_path: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
description: 'The absolute path where the .docx file should be saved'
|
|
45
|
+
},
|
|
46
|
+
content: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'The text content to write into the document'
|
|
49
|
+
},
|
|
50
|
+
title: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Optional title for the document'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
required: ['file_path', 'content']
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async execute(args, _ctx) {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
try {
|
|
61
|
+
const docx = officegen('docx');
|
|
62
|
+
docx.on('error', (err) => {
|
|
63
|
+
resolve({ error: `Officegen error: ${err}` });
|
|
64
|
+
});
|
|
65
|
+
if (args.title) {
|
|
66
|
+
const pObj = docx.createP();
|
|
67
|
+
pObj.addText(args.title, { bold: true, font_size: 24 });
|
|
68
|
+
}
|
|
69
|
+
const paragraphs = args.content.split('\n');
|
|
70
|
+
for (const para of paragraphs) {
|
|
71
|
+
if (para.trim()) {
|
|
72
|
+
const pObj = docx.createP();
|
|
73
|
+
pObj.addText(para);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const out = fs.createWriteStream(args.file_path);
|
|
77
|
+
out.on('error', (err) => {
|
|
78
|
+
resolve({ error: `File write error: ${err}` });
|
|
79
|
+
});
|
|
80
|
+
out.on('close', () => {
|
|
81
|
+
resolve({ success: true, message: `Word file created at ${args.file_path}` });
|
|
82
|
+
});
|
|
83
|
+
docx.generate(out);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
resolve({ error: `Failed to create Word file: ${error.message}` });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a user authentication API route demo.
|
|
3
|
+
* Handle user registration, login, token management, etc.
|
|
4
|
+
*/
|
|
5
|
+
import { Router } from 'express';
|
|
6
|
+
const router = Router();
|
|
7
|
+
/**
|
|
8
|
+
* User Login
|
|
9
|
+
* POST /api/auth/register
|
|
10
|
+
*/
|
|
11
|
+
router.post('/register', async (req, res) => {
|
|
12
|
+
// TODO: Implement register logic
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* User Login
|
|
16
|
+
* POST /api/auth/login
|
|
17
|
+
*/
|
|
18
|
+
router.post('/login', async (req, res) => {
|
|
19
|
+
// TODO: Implement login logic
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* User Logout
|
|
23
|
+
* POST /api/auth/logout
|
|
24
|
+
*/
|
|
25
|
+
router.post('/logout', async (req, res) => {
|
|
26
|
+
// TODO: Implement logout logic
|
|
27
|
+
});
|
|
28
|
+
export default router;
|