-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatch.js
More file actions
207 lines (184 loc) · 9.92 KB
/
Copy pathpatch.js
File metadata and controls
207 lines (184 loc) · 9.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
const fs = require('fs');
let content = fs.readFileSync('bin/index.js', 'utf8');
// 1. Update generateSkillMd
const newInstruction = `
} else if (templateType === 'dynamic-request') {
instructions = \`## 导出的核心方法\\n\\n### 1. \\\\`getJinaReaderContent(targetUrl, config)\\\`\\n- **功能**:自动抓取目标网页,并返回纯净的 Markdown 文本。\\n- **返回值**:网页纯文本内容\\n\\n### 2. \\\\`fetchRequest(url, config, fullResponse)\\\`\\n- **功能**:通用的网络请求封装。默认 30s 超时。\\n\\n---\\n\\n## Agent 使用示例\\n\\n\` + codeSnippet + \`\\n\\n---\\n\\n## 🤖 Agent 动态技能扩展指令\\n\\n如果你(AI Agent)在与用户的对话中识别到指令关键词 **“添加SKILL”** 或 **“添加Request”**,且用户附带了目标接口信息(可以是一个纯 URL,也可以是一段完整的 cURL 或 Postman 代码等),请严格执行以下标准化工作流:\\n\\n1. **分析并精简输入内容**:\\n - 解析出目标接口的 URL、请求方法、必需的 Headers 以及 Payload 参数。\\n - **核心过滤规则**:剔除所有非必需的参数和 Headers(例如 \\\`sec-ch-ua-\\\`、\\\`accept-encoding\\\` 等),保持极简。\\n2. **转换调用代码**:\\n - **绝对不要修改底层的 request 代码**。\\n - 将精简后的请求参数转换为一段调用代码,直接引入并调用 \\\`fetchRequest\\\` 或 \\\`getJinaReaderContent\\\`。\\n3. **更新技能文档**:\\n - 将转换好的调用代码作为一个新的【示例 X】,追加补充到本 SKILL.md 文件的 **“Agent 使用示例”** 章节中。\\n - 以后当需要访问该接口时,直接复用示例中的代码即可。\`;
} else if (templateType === 'choice') {
`;
content = content.replace(" } else if (templateType === 'choice') {", newInstruction);
// 2. Update python injection
const pythonInjection = `
if (language === 'python') {
await fs.ensureDir(path.join(targetPath, 'scripts'));
await fs.writeFile(
path.join(targetPath, 'requirements.txt'),
\`requests\\npython-dotenv\\n\`
);
if (response.templateType === 'dynamic-request') {
const pyCode = \`import requests
from typing import Any, Dict, Optional, Union
def fetch_request(url: str, config: Optional[Dict[str, Any]] = None, full_response: bool = False) -> Union[Any, Dict[str, Any]]:
config = config or {}
timeout = config.pop('timeout', 30)
method = config.pop('method', 'GET').upper()
try:
res = requests.request(method, url, timeout=timeout, **config)
res.raise_for_status()
content_type = res.headers.get('content-type', '')
data = res.json() if 'application/json' in content_type else res.text
if full_response:
return {'data': data, 'status': res.status_code, 'statusText': res.reason, 'headers': dict(res.headers)}
return data
except requests.RequestException as e:
print(f"[fetch_request] failed for {url}: {e}")
raise
def get_jina_reader_content(target_url: str, config: Optional[Dict[str, Any]] = None) -> str:
jina_url = f"https://r.jina.ai/{target_url}"
config = config or {}
config['method'] = 'GET'
return fetch_request(jina_url, config=config, full_response=False)
\`;
await fs.writeFile(path.join(targetPath, 'scripts', 'request.py'), pyCode);
await fs.writeFile(
path.join(targetPath, 'scripts', 'main.py'),
\`from request import get_jina_reader_content\\n\\ndef main():\\n print(get_jina_reader_content("https://example.com"))\\n\\nif __name__ == "__main__":\\n main()\\n\`
);
} else {
await fs.writeFile(
path.join(targetPath, 'scripts', 'main.py'),
\`import os\\nfrom dotenv import load_dotenv\\n\\nload_dotenv()\\n\\ndef main():\\n print("Hello from \${targetDir}!")\\n\\nif __name__ == "__main__":\\n main()\\n\`
);
}
}
`;
content = content.replace(/ if \(language === 'python'\) \{[\s\S]*? \} else if \(language === 'javascript'\) \{/, pythonInjection.trim() + " else if (language === 'javascript') {");
// 3. Update js injection
const jsInjection = `
} else if (language === 'javascript') {
await fs.ensureDir(path.join(targetPath, 'scripts'));
await fs.writeFile(
path.join(targetPath, 'package.json'),
JSON.stringify({
name: targetDir,
version: "0.0.1",
description: description,
main: "scripts/index.js",
scripts: { "start": "node scripts/index.js" },
dependencies: { "dotenv": "^16.4.5" }
}, null, 2)
);
if (response.templateType === 'dynamic-request') {
const jsCode = \`async function fetchRequest(url, options = {}, fullResponse = false) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options.timeout || 30000);
try {
const res = await fetch(url, { ...options, signal: controller.signal });
const contentType = res.headers.get('content-type') || '';
let data;
if (contentType.includes('application/json')) {
data = await res.json();
} else {
data = await res.text();
}
if (fullResponse) {
const headers = {};
res.headers.forEach((value, key) => { headers[key] = value; });
return { data, status: res.status, statusText: res.statusText, headers };
}
return data;
} catch (err) {
console.error(\\\`[fetchRequest] failed for \\\${url}:\\\`, err);
throw err;
} finally {
clearTimeout(timeoutId);
}
}
async function getJinaReaderContent(targetUrl, options = {}) {
const jinaUrl = \\\`https://r.jina.ai/\\\${targetUrl}\\\`;
return fetchRequest(jinaUrl, { method: 'GET', ...options });
}
module.exports = { fetchRequest, getJinaReaderContent };
\`;
await fs.writeFile(path.join(targetPath, 'scripts', 'request.js'), jsCode);
await fs.writeFile(
path.join(targetPath, 'scripts', 'index.js'),
\`const { getJinaReaderContent } = require('./request.js');\\n\\nasync function main() {\\n console.log(await getJinaReaderContent('https://example.com'));\\n}\\nmain();\\n\`
);
} else {
await fs.writeFile(
path.join(targetPath, 'scripts', 'index.js'),
\`require('dotenv').config();\\n\\nfunction main() {\\n console.log('Hello from \${targetDir}!');\\n}\\n\\nmain();\\n\`
);
}
}
`;
content = content.replace(/ \} else if \(language === 'javascript'\) \{[\s\S]*? \} else if \(language === 'typescript'\) \{/, jsInjection.trim() + " else if (language === 'typescript') {");
// 4. Update TS injection
const tsInjection = `
} else if (language === 'typescript') {
const tsPath = path.join(targetPath, 'src-ts');
// Modify Rollup configuration to output to ../scripts/
const rollupPath = path.join(tsPath, 'rollup.config.js');
if (fs.existsSync(rollupPath)) {
let rollupConfig = await fs.readFile(rollupPath, 'utf-8');
rollupConfig = rollupConfig.replace(/file: 'lib\\//g, "file: '../scripts/");
rollupConfig = rollupConfig.replace(/dir: 'lib'/g, "dir: '../scripts'");
await fs.writeFile(rollupPath, rollupConfig);
}
// Modify tsconfig.json to output to ../scripts/
const tsconfigPath = path.join(tsPath, 'tsconfig.json');
if (fs.existsSync(tsconfigPath)) {
let tsconfig = await fs.readFile(tsconfigPath, 'utf-8');
tsconfig = tsconfig.replace(/"outDir":\\s*"lib"/g, '"outDir": "../scripts"');
await fs.writeFile(tsconfigPath, tsconfig);
}
// Modify package.json to point main/module to ../scripts/
const pkgPath = path.join(tsPath, 'package.json');
if (fs.existsSync(pkgPath)) {
const pkg = await fs.readJson(pkgPath);
if (pkg.main) pkg.main = pkg.main.replace('lib/', '../scripts/');
if (pkg.module) pkg.module = pkg.module.replace('lib/', '../scripts/');
if (pkg.types) pkg.types = pkg.types.replace('lib/', '../scripts/');
pkg.dependencies = pkg.dependencies || {};
pkg.dependencies['dotenv'] = '^16.4.5';
if (response.templateType === 'dynamic-request') {
pkg.dependencies['axios'] = '^1.7.9';
}
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
}
if (response.templateType === 'dynamic-request') {
const tsCode = \`import axios, { AxiosRequestConfig } from 'axios';
export interface UnifiedResponse<T = any> {
data: T;
status: number;
statusText: string;
headers: Record<string, string>;
}
export async function fetchRequest<T = any>(url: string, config?: AxiosRequestConfig, fullResponse?: false): Promise<T>;
export async function fetchRequest<T = any>(url: string, config?: AxiosRequestConfig, fullResponse?: true): Promise<UnifiedResponse<T>>;
export async function fetchRequest<T = any>(url: string, config?: AxiosRequestConfig, fullResponse: boolean = false): Promise<T | UnifiedResponse<T>> {
const defaultConfig: AxiosRequestConfig = { timeout: 30000, ...config };
try {
const response = await axios(url, defaultConfig);
if (fullResponse) {
return { data: response.data, status: response.status, statusText: response.statusText, headers: response.headers as Record<string, string> };
}
return response.data;
} catch (error) {
console.error(\\\`[fetchRequest] failed for \\\${url}:\\\`, error);
throw error;
}
}
export async function getJinaReaderContent(targetUrl: string, config?: AxiosRequestConfig): Promise<string> {
const jinaUrl = \\\`https://r.jina.ai/\\\${targetUrl}\\\`;
return await fetchRequest<string>(jinaUrl, { method: 'GET', ...config });
}
\`;
await fs.writeFile(path.join(tsPath, 'src', 'request.ts'), tsCode);
await fs.writeFile(path.join(tsPath, 'src', 'index.ts'), \`export * from './request';\\n\`);
}
}
`;
content = content.replace(/ \} else if \(language === 'typescript'\) \{[\s\S]*?pkg\.dependencies\['dotenv'\] = '\^16\.4\.5';[\s\S]*?await fs\.writeJson\(pkgPath, pkg, \{ spaces: 2 \}\);\n \}\n \}/, tsInjection.trim());
fs.writeFileSync('bin/index.js', content);