openkbs 0.0.67 → 0.0.70
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 +1 -0
- package/elastic/README.md +1 -1
- package/elastic/functions.md +5 -5
- package/elastic/pulse.md +2 -2
- package/package.json +2 -2
- package/scripts/deploy.js +68 -0
- package/src/actions.js +7 -0
- package/templates/.claude/skills/openkbs/SKILL.md +37 -8
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/README.md +55 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/instructions.txt +40 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/app/settings.json +41 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/openkbs.json +3 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/actions.js +141 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/handler.js +32 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/memoryHelpers.js +91 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onCronjob.js +105 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onPublicAPIRequest.js +165 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onRequest.js +2 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Events/onResponse.js +2 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.js +74 -0
- package/templates/.claude/skills/openkbs/examples/monitoring-bot/src/Frontend/contentRender.json +3 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/index.mjs +228 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/auth/package.json +7 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/index.mjs +287 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/posts/package.json +10 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/functions/settings.json +4 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/openkbs.json +16 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/index.html +658 -0
- package/templates/.claude/skills/openkbs/examples/nodejs-demo/site/settings.json +4 -0
- package/templates/.claude/skills/openkbs/patterns/cronjob-batch-processing.md +278 -0
- package/templates/.claude/skills/openkbs/patterns/cronjob-monitoring.md +341 -0
- package/templates/.claude/skills/openkbs/patterns/file-upload.md +205 -0
- package/templates/.claude/skills/openkbs/patterns/image-generation.md +139 -0
- package/templates/.claude/skills/openkbs/patterns/memory-system.md +264 -0
- package/templates/.claude/skills/openkbs/patterns/public-api-item-proxy.md +254 -0
- package/templates/.claude/skills/openkbs/patterns/scheduled-tasks.md +157 -0
- package/templates/.claude/skills/openkbs/patterns/telegram-webhook.md +424 -0
- package/templates/.claude/skills/openkbs/patterns/telegram.md +222 -0
- package/templates/.claude/skills/openkbs/patterns/vectordb-archive.md +231 -0
- package/templates/.claude/skills/openkbs/patterns/video-generation.md +145 -0
- package/templates/.claude/skills/openkbs/patterns/web-publishing.md +257 -0
- package/templates/.claude/skills/openkbs/reference/backend-sdk.md +13 -2
- package/templates/.claude/skills/openkbs/reference/elastic-services.md +61 -29
- package/templates/platform/README.md +15 -50
- package/templates/platform/agents/assistant/app/icon.png +0 -0
- package/templates/platform/agents/assistant/app/instructions.txt +9 -21
- package/templates/platform/agents/assistant/app/settings.json +11 -15
- package/templates/platform/agents/assistant/src/Events/actions.js +31 -62
- package/templates/platform/agents/assistant/src/Events/handler.js +54 -0
- package/templates/platform/agents/assistant/src/Events/onRequest.js +3 -0
- package/templates/platform/agents/assistant/src/Events/onRequest.json +5 -0
- package/templates/platform/agents/assistant/src/Events/onResponse.js +2 -40
- package/templates/platform/agents/assistant/src/Events/onResponse.json +4 -2
- package/templates/platform/agents/assistant/src/Frontend/contentRender.js +17 -16
- package/templates/platform/agents/assistant/src/Frontend/contentRender.json +1 -1
- package/templates/platform/functions/api/index.mjs +17 -23
- package/templates/platform/functions/api/package.json +4 -0
- package/templates/platform/openkbs.json +7 -2
- package/templates/platform/site/index.html +18 -19
- package/version.json +3 -3
- package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/run_job.js +0 -26
- package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/utils/agent_client.js +0 -265
|
@@ -1,51 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* {{APP_NAME}} API
|
|
3
3
|
*
|
|
4
|
-
* Endpoint: https://
|
|
4
|
+
* Endpoint: https://yourdomain.com/api
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
6
|
+
* Environment variables:
|
|
7
|
+
* - DATABASE_URL (Postgres connection string)
|
|
8
|
+
* - STORAGE_BUCKET (S3 bucket name)
|
|
9
|
+
* - OPENKBS_KB_ID (your kbId)
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
export const handler = async (event) => {
|
|
12
|
-
const body = JSON.parse(event.body || '{}');
|
|
13
|
-
const { action, data } = body;
|
|
14
|
-
|
|
15
|
-
// CORS headers
|
|
16
13
|
const headers = {
|
|
17
14
|
'Content-Type': 'application/json',
|
|
18
15
|
'Access-Control-Allow-Origin': '*',
|
|
19
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
20
16
|
'Access-Control-Allow-Headers': 'Content-Type'
|
|
21
17
|
};
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
if (event.httpMethod === 'OPTIONS') {
|
|
19
|
+
if (event.requestContext?.http?.method === 'OPTIONS') {
|
|
25
20
|
return { statusCode: 200, headers, body: '' };
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
try {
|
|
24
|
+
const body = JSON.parse(event.body || '{}');
|
|
25
|
+
const { action } = body;
|
|
26
|
+
|
|
29
27
|
switch (action) {
|
|
30
28
|
case 'hello':
|
|
31
29
|
return {
|
|
32
30
|
statusCode: 200,
|
|
33
31
|
headers,
|
|
34
32
|
body: JSON.stringify({
|
|
35
|
-
message: 'Hello from {{APP_NAME}}
|
|
36
|
-
timestamp: new Date().toISOString()
|
|
37
|
-
input: data
|
|
33
|
+
message: 'Hello from {{APP_NAME}}!',
|
|
34
|
+
timestamp: new Date().toISOString()
|
|
38
35
|
})
|
|
39
36
|
};
|
|
40
37
|
|
|
41
|
-
case '
|
|
38
|
+
case 'status':
|
|
42
39
|
return {
|
|
43
40
|
statusCode: 200,
|
|
44
41
|
headers,
|
|
45
42
|
body: JSON.stringify({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
postgres: !!process.env.DATABASE_URL,
|
|
44
|
+
storage: !!process.env.STORAGE_BUCKET,
|
|
45
|
+
kbId: process.env.OPENKBS_KB_ID
|
|
49
46
|
})
|
|
50
47
|
};
|
|
51
48
|
|
|
@@ -53,10 +50,7 @@ export const handler = async (event) => {
|
|
|
53
50
|
return {
|
|
54
51
|
statusCode: 400,
|
|
55
52
|
headers,
|
|
56
|
-
body: JSON.stringify({
|
|
57
|
-
error: 'Unknown action',
|
|
58
|
-
availableActions: ['hello', 'health']
|
|
59
|
-
})
|
|
53
|
+
body: JSON.stringify({ error: 'Unknown action', available: ['hello', 'status'] })
|
|
60
54
|
};
|
|
61
55
|
}
|
|
62
56
|
} catch (error) {
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
+
"name": "{{APP_NAME}}",
|
|
3
|
+
"region": "us-east-1",
|
|
4
|
+
|
|
2
5
|
"elastic": {
|
|
3
6
|
"postgres": true,
|
|
4
|
-
"storage":
|
|
7
|
+
"storage": {
|
|
8
|
+
"cloudfront": "media"
|
|
9
|
+
},
|
|
5
10
|
"pulse": true,
|
|
6
11
|
"functions": {
|
|
7
12
|
"api": {
|
|
8
|
-
"runtime": "
|
|
13
|
+
"runtime": "nodejs24.x",
|
|
9
14
|
"memory": 512,
|
|
10
15
|
"timeout": 30
|
|
11
16
|
}
|
|
@@ -31,27 +31,28 @@
|
|
|
31
31
|
color: white;
|
|
32
32
|
text-decoration: none;
|
|
33
33
|
border-radius: 8px;
|
|
34
|
+
border: none;
|
|
34
35
|
font-weight: 600;
|
|
35
|
-
|
|
36
|
+
cursor: pointer;
|
|
36
37
|
}
|
|
37
|
-
.btn:hover {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
.btn:hover { opacity: 0.9; }
|
|
39
|
+
pre {
|
|
40
|
+
margin-top: 2rem;
|
|
41
|
+
text-align: left;
|
|
42
|
+
background: #f5f5f5;
|
|
43
|
+
padding: 1rem;
|
|
44
|
+
border-radius: 8px;
|
|
45
|
+
display: none;
|
|
46
|
+
overflow: auto;
|
|
40
47
|
}
|
|
41
|
-
.links { margin-top: 2rem; }
|
|
42
|
-
.links a { color: #667eea; margin: 0 10px; }
|
|
43
48
|
</style>
|
|
44
49
|
</head>
|
|
45
50
|
<body>
|
|
46
51
|
<div class="container">
|
|
47
52
|
<h1>{{APP_NAME}}</h1>
|
|
48
|
-
<p>Your OpenKBS platform is ready
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
<a href="https://openkbs.com/docs">Documentation</a>
|
|
52
|
-
<a href="https://github.com/open-kbs/openkbs">GitHub</a>
|
|
53
|
-
</div>
|
|
54
|
-
<pre id="result" style="margin-top: 2rem; text-align: left; background: #f5f5f5; padding: 1rem; border-radius: 8px; display: none;"></pre>
|
|
53
|
+
<p>Your OpenKBS platform is ready.</p>
|
|
54
|
+
<button class="btn" onclick="testAPI()">Test API</button>
|
|
55
|
+
<pre id="result"></pre>
|
|
55
56
|
</div>
|
|
56
57
|
<script>
|
|
57
58
|
async function testAPI() {
|
|
@@ -59,16 +60,14 @@
|
|
|
59
60
|
result.style.display = 'block';
|
|
60
61
|
result.textContent = 'Loading...';
|
|
61
62
|
try {
|
|
62
|
-
|
|
63
|
-
const response = await fetch('/api', {
|
|
63
|
+
const res = await fetch('/api', {
|
|
64
64
|
method: 'POST',
|
|
65
65
|
headers: { 'Content-Type': 'application/json' },
|
|
66
|
-
body: JSON.stringify({ action: 'hello'
|
|
66
|
+
body: JSON.stringify({ action: 'hello' })
|
|
67
67
|
});
|
|
68
|
-
|
|
69
|
-
result.textContent = JSON.stringify(data, null, 2);
|
|
68
|
+
result.textContent = JSON.stringify(await res.json(), null, 2);
|
|
70
69
|
} catch (e) {
|
|
71
|
-
result.textContent = 'Error: ' + e.message
|
|
70
|
+
result.textContent = 'Error: ' + e.message;
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
</script>
|
package/version.json
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// This boilerplate code is a starting point for development.
|
|
2
|
-
|
|
3
|
-
const OpenKBSAgentClient = require('./utils/agent_client');
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
const client = new OpenKBSAgentClient();
|
|
7
|
-
|
|
8
|
-
const message = `Today's Date: ${new Date().toLocaleDateString()}
|
|
9
|
-
|
|
10
|
-
PROCESS_PRODUCT:
|
|
11
|
-
Product Name: iPhone 14 Pro Max
|
|
12
|
-
Product Code: MQ9X3RX/A
|
|
13
|
-
ID: 97649
|
|
14
|
-
|
|
15
|
-
find at least 2 images and 2 videos
|
|
16
|
-
`;
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const result = await client.runJob(message);
|
|
20
|
-
console.log('Job completed:', result);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error('Job failed:', error.message);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
main();
|
package/templates/.claude/skills/openkbs/examples/ai-copywriter-agent/scripts/utils/agent_client.js
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
const https = require('https');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const readline = require('readline');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { URL } = require('url');
|
|
6
|
-
|
|
7
|
-
class OpenKBSAgentClient {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.settings = this.findSettings();
|
|
10
|
-
this.secretsPath = this.findSecretsPath();
|
|
11
|
-
this.apiKey = null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
findSettings() {
|
|
15
|
-
let currentDir = __dirname;
|
|
16
|
-
|
|
17
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
18
|
-
const settingsPath = path.join(currentDir, 'app', 'settings.json');
|
|
19
|
-
if (fs.existsSync(settingsPath)) {
|
|
20
|
-
return JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
21
|
-
}
|
|
22
|
-
currentDir = path.dirname(currentDir);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
throw new Error('Could not find app/settings.json in parent directories');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
findSecretsPath() {
|
|
29
|
-
let currentDir = __dirname;
|
|
30
|
-
|
|
31
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
32
|
-
const settingsPath = path.join(currentDir, 'app', 'settings.json');
|
|
33
|
-
if (fs.existsSync(settingsPath)) {
|
|
34
|
-
const secretsPath = path.join(currentDir, '.openkbs', 'secrets.json');
|
|
35
|
-
return secretsPath;
|
|
36
|
-
}
|
|
37
|
-
currentDir = path.dirname(currentDir);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
throw new Error('Could not find agent directory with app/settings.json');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async getApiKey() {
|
|
44
|
-
if (this.apiKey) return this.apiKey;
|
|
45
|
-
|
|
46
|
-
if (fs.existsSync(this.secretsPath)) {
|
|
47
|
-
const secrets = JSON.parse(fs.readFileSync(this.secretsPath, 'utf8'));
|
|
48
|
-
this.apiKey = secrets.apiKey;
|
|
49
|
-
return this.apiKey;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.apiKey = await this.promptForApiKey();
|
|
53
|
-
this.saveApiKey(this.apiKey);
|
|
54
|
-
return this.apiKey;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async init() {
|
|
58
|
-
await this.getApiKey();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async promptForApiKey() {
|
|
62
|
-
return new Promise((resolve) => {
|
|
63
|
-
const rl = readline.createInterface({
|
|
64
|
-
input: process.stdin,
|
|
65
|
-
output: process.stdout
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
console.log(`Please generate an API key from: https://${this.settings.kbId}.apps.openkbs.com/?tab=access&createAPIKey=api-${+new Date()}`);
|
|
69
|
-
|
|
70
|
-
rl.question('Enter your API key: ', (key) => {
|
|
71
|
-
rl.close();
|
|
72
|
-
resolve(key);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
rl._writeToOutput = (str) => {
|
|
76
|
-
if (str === '\n' || str === '\r\n') {
|
|
77
|
-
rl.output.write(str);
|
|
78
|
-
} else if (str.match(/[\x08\x7f]/)) {
|
|
79
|
-
rl.output.write(str);
|
|
80
|
-
} else if (rl.line && str.length === 1) {
|
|
81
|
-
rl.output.write('*');
|
|
82
|
-
} else {
|
|
83
|
-
rl.output.write(str);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
saveApiKey(key) {
|
|
90
|
-
const secretsDir = path.dirname(this.secretsPath);
|
|
91
|
-
if (!fs.existsSync(secretsDir)) {
|
|
92
|
-
fs.mkdirSync(secretsDir, { recursive: true });
|
|
93
|
-
}
|
|
94
|
-
fs.writeFileSync(this.secretsPath, JSON.stringify({ apiKey: key }, null, 2));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Run a job and get response from the agent
|
|
99
|
-
*
|
|
100
|
-
* @param {string|Array} message - Either:
|
|
101
|
-
* - String: "Do something ..."
|
|
102
|
-
* - Array: [
|
|
103
|
-
* {type:"text", text:"Process this invoice"},
|
|
104
|
-
* {type:"image_url", image_url:{url:"https://files.openkbs.com/invoice.png"}}
|
|
105
|
-
* ]
|
|
106
|
-
*
|
|
107
|
-
* @returns {Promise<Object>} Response structure:
|
|
108
|
-
* {
|
|
109
|
-
* data: {
|
|
110
|
-
* type: 'TEXT' | 'CUSTOM_TYPE',
|
|
111
|
-
* content: '...' | data: {...}
|
|
112
|
-
* },
|
|
113
|
-
* chatId: 'xxx-xxx',
|
|
114
|
-
* msgId: 'msg_xxx'
|
|
115
|
-
* }
|
|
116
|
-
*/
|
|
117
|
-
async runJob(message, options = {}) {
|
|
118
|
-
const apiKey = await this.getApiKey();
|
|
119
|
-
if (!this.settings.kbId) throw new Error('First use: "openkbs push" to create the agent');
|
|
120
|
-
|
|
121
|
-
const payload = { message };
|
|
122
|
-
Object.keys(options).forEach(key => {
|
|
123
|
-
if (key === 'historyLimit') {
|
|
124
|
-
payload[key] = Math.min(Math.max(1, options[key]), 100);
|
|
125
|
-
} else if (options[key] !== undefined) {
|
|
126
|
-
payload[key] = options[key];
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const response = await this.request(
|
|
131
|
-
`https://${this.settings.kbId}.apps.openkbs.com/api`,
|
|
132
|
-
payload,
|
|
133
|
-
{ Authorization: `Bearer ${apiKey}` }
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
if (response.chatId) this.lastChatId = response.chatId;
|
|
137
|
-
return response;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async continueChat(message, chatId = null, options = {}) {
|
|
141
|
-
const targetChatId = chatId || this.lastChatId;
|
|
142
|
-
if (!targetChatId) throw new Error('No chatId provided and no previous chat to continue');
|
|
143
|
-
|
|
144
|
-
return this.runJob(message, {
|
|
145
|
-
...options,
|
|
146
|
-
chatId: targetChatId,
|
|
147
|
-
includeHistory: options.includeHistory !== false
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async uploadFile(filePath, options = {}) {
|
|
152
|
-
const apiKey = await this.getApiKey();
|
|
153
|
-
if (!fs.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
154
|
-
|
|
155
|
-
const fileContent = fs.readFileSync(filePath);
|
|
156
|
-
const ext = path.extname(filePath);
|
|
157
|
-
const fileName = options.fileName || `file-${Date.now()}-${Math.random().toString(36).substring(7)}${ext}`;
|
|
158
|
-
const fileType = options.fileType || this.getMimeType(filePath);
|
|
159
|
-
|
|
160
|
-
const presignedResponse = await this.request('https://kb.openkbs.com/', {
|
|
161
|
-
apiKey,
|
|
162
|
-
kbId: this.settings.kbId,
|
|
163
|
-
namespace: 'files',
|
|
164
|
-
presignedOperation: 'putObject',
|
|
165
|
-
action: 'createPresignedURL',
|
|
166
|
-
fileName,
|
|
167
|
-
fileType
|
|
168
|
-
}, { Origin: `https://${this.settings.kbId}.apps.openkbs.com` });
|
|
169
|
-
|
|
170
|
-
const presignedUrl = presignedResponse.presignedUrl || presignedResponse;
|
|
171
|
-
|
|
172
|
-
await this.requestRaw(presignedUrl, fileContent, {
|
|
173
|
-
'Content-Type': fileType,
|
|
174
|
-
'Content-Length': fileContent.length
|
|
175
|
-
}, 'PUT');
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
fileName,
|
|
179
|
-
uploaded: true,
|
|
180
|
-
url: `https://file.openkbs.com/files/${this.settings.kbId}/${fileName}`
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
getMimeType(filePath) {
|
|
185
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
186
|
-
const mimeTypes = {
|
|
187
|
-
'.pdf': 'application/pdf',
|
|
188
|
-
'.txt': 'text/plain',
|
|
189
|
-
'.json': 'application/json',
|
|
190
|
-
'.jpg': 'image/jpeg',
|
|
191
|
-
'.jpeg': 'image/jpeg',
|
|
192
|
-
'.png': 'image/png',
|
|
193
|
-
'.gif': 'image/gif',
|
|
194
|
-
'.doc': 'application/msword',
|
|
195
|
-
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
196
|
-
'.xls': 'application/vnd.ms-excel',
|
|
197
|
-
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
198
|
-
'.csv': 'text/csv',
|
|
199
|
-
'.html': 'text/html',
|
|
200
|
-
'.xml': 'application/xml',
|
|
201
|
-
'.zip': 'application/zip'
|
|
202
|
-
};
|
|
203
|
-
return mimeTypes[ext] || 'application/octet-stream';
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Unified HTTP request helper
|
|
207
|
-
async request(url, payload, headers = {}, method = 'POST') {
|
|
208
|
-
return new Promise((resolve, reject) => {
|
|
209
|
-
const { hostname, pathname, search } = new URL(url);
|
|
210
|
-
const req = https.request({
|
|
211
|
-
hostname,
|
|
212
|
-
path: pathname + (search || ''),
|
|
213
|
-
method,
|
|
214
|
-
headers: { 'Content-Type': 'application/json', ...headers }
|
|
215
|
-
}, res => {
|
|
216
|
-
let data = '';
|
|
217
|
-
res.on('data', chunk => data += chunk);
|
|
218
|
-
res.on('end', () => {
|
|
219
|
-
try {
|
|
220
|
-
const result = JSON.parse(data);
|
|
221
|
-
if (res.statusCode === 401) {
|
|
222
|
-
if (fs.existsSync(this.secretsPath)) fs.unlinkSync(this.secretsPath);
|
|
223
|
-
reject(new Error('Authentication failed. Please run "node scripts/run_job.js init" to reconfigure.'));
|
|
224
|
-
} else if (res.statusCode !== 200) {
|
|
225
|
-
reject(new Error(`Request failed with status ${res.statusCode}: ${data}`));
|
|
226
|
-
} else {
|
|
227
|
-
resolve(result);
|
|
228
|
-
}
|
|
229
|
-
} catch (error) {
|
|
230
|
-
reject(new Error(`Failed to parse response: ${error.message}`));
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
}).on('error', reject);
|
|
234
|
-
|
|
235
|
-
req.write(typeof payload === 'string' ? payload : JSON.stringify(payload));
|
|
236
|
-
req.end();
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Raw request for binary data
|
|
241
|
-
async requestRaw(url, data, headers = {}, method = 'PUT') {
|
|
242
|
-
return new Promise((resolve, reject) => {
|
|
243
|
-
const { hostname, pathname, search } = new URL(url);
|
|
244
|
-
const req = https.request({
|
|
245
|
-
hostname,
|
|
246
|
-
path: pathname + (search || ''),
|
|
247
|
-
method,
|
|
248
|
-
headers
|
|
249
|
-
}, res => {
|
|
250
|
-
if (res.statusCode === 200 || res.statusCode === 204) {
|
|
251
|
-
resolve();
|
|
252
|
-
} else {
|
|
253
|
-
let responseData = '';
|
|
254
|
-
res.on('data', chunk => responseData += chunk);
|
|
255
|
-
res.on('end', () => reject(new Error(`Request failed with status ${res.statusCode}: ${responseData}`)));
|
|
256
|
-
}
|
|
257
|
-
}).on('error', reject);
|
|
258
|
-
|
|
259
|
-
req.write(data);
|
|
260
|
-
req.end();
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
module.exports = OpenKBSAgentClient;
|