opc-agent 3.0.1 → 4.0.1
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 +404 -74
- package/README.zh-CN.md +82 -0
- package/dist/channels/dingtalk.d.ts +17 -0
- package/dist/channels/dingtalk.js +38 -0
- package/dist/channels/googlechat.d.ts +14 -0
- package/dist/channels/googlechat.js +37 -0
- package/dist/channels/imessage.d.ts +13 -0
- package/dist/channels/imessage.js +28 -0
- package/dist/channels/irc.d.ts +20 -0
- package/dist/channels/irc.js +71 -0
- package/dist/channels/line.d.ts +14 -0
- package/dist/channels/line.js +28 -0
- package/dist/channels/matrix.d.ts +15 -0
- package/dist/channels/matrix.js +28 -0
- package/dist/channels/mattermost.d.ts +18 -0
- package/dist/channels/mattermost.js +49 -0
- package/dist/channels/msteams.d.ts +14 -0
- package/dist/channels/msteams.js +28 -0
- package/dist/channels/nostr.d.ts +14 -0
- package/dist/channels/nostr.js +28 -0
- package/dist/channels/qq.d.ts +15 -0
- package/dist/channels/qq.js +28 -0
- package/dist/channels/signal.d.ts +14 -0
- package/dist/channels/signal.js +28 -0
- package/dist/channels/sms.d.ts +15 -0
- package/dist/channels/sms.js +28 -0
- package/dist/channels/twitch.d.ts +17 -0
- package/dist/channels/twitch.js +59 -0
- package/dist/channels/voice-call.d.ts +27 -0
- package/dist/channels/voice-call.js +82 -0
- package/dist/channels/whatsapp.d.ts +14 -0
- package/dist/channels/whatsapp.js +28 -0
- package/dist/cli/chat.d.ts +2 -0
- package/dist/cli/chat.js +134 -0
- package/dist/cli/setup.d.ts +4 -0
- package/dist/cli/setup.js +303 -0
- package/dist/cli.js +142 -6
- package/dist/core/api-server.d.ts +25 -0
- package/dist/core/api-server.js +286 -0
- package/dist/core/audio.d.ts +50 -0
- package/dist/core/audio.js +68 -0
- package/dist/core/context-discovery.d.ts +16 -0
- package/dist/core/context-discovery.js +107 -0
- package/dist/core/context-refs.d.ts +29 -0
- package/dist/core/context-refs.js +162 -0
- package/dist/core/gateway.d.ts +53 -0
- package/dist/core/gateway.js +80 -0
- package/dist/core/heartbeat.d.ts +19 -0
- package/dist/core/heartbeat.js +50 -0
- package/dist/core/hooks.d.ts +28 -0
- package/dist/core/hooks.js +82 -0
- package/dist/core/ide-bridge.d.ts +53 -0
- package/dist/core/ide-bridge.js +97 -0
- package/dist/core/node-network.d.ts +23 -0
- package/dist/core/node-network.js +77 -0
- package/dist/core/profiles.d.ts +27 -0
- package/dist/core/profiles.js +131 -0
- package/dist/core/sandbox.d.ts +25 -0
- package/dist/core/sandbox.js +84 -1
- package/dist/core/session-manager.d.ts +33 -0
- package/dist/core/session-manager.js +157 -0
- package/dist/core/vision.d.ts +45 -0
- package/dist/core/vision.js +177 -0
- package/dist/hub/brain-seed.d.ts +14 -0
- package/dist/hub/brain-seed.js +77 -0
- package/dist/hub/client.d.ts +25 -0
- package/dist/hub/client.js +44 -0
- package/dist/index.d.ts +66 -1
- package/dist/index.js +95 -3
- package/dist/memory/context-compressor.d.ts +43 -0
- package/dist/memory/context-compressor.js +167 -0
- package/dist/memory/index.d.ts +4 -0
- package/dist/memory/index.js +5 -1
- package/dist/memory/user-profiler.d.ts +50 -0
- package/dist/memory/user-profiler.js +201 -0
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.js +54 -1
- package/dist/scheduler/cron-engine.d.ts +41 -0
- package/dist/scheduler/cron-engine.js +200 -0
- package/dist/scheduler/index.d.ts +3 -0
- package/dist/scheduler/index.js +7 -0
- package/dist/schema/oad.d.ts +12 -12
- package/dist/security/approvals.d.ts +53 -0
- package/dist/security/approvals.js +115 -0
- package/dist/security/elevated.d.ts +41 -0
- package/dist/security/elevated.js +89 -0
- package/dist/security/index.d.ts +6 -0
- package/dist/security/index.js +7 -1
- package/dist/security/secrets.d.ts +34 -0
- package/dist/security/secrets.js +115 -0
- package/dist/skills/builtin/index.d.ts +6 -0
- package/dist/skills/builtin/index.js +402 -0
- package/dist/skills/marketplace.d.ts +30 -0
- package/dist/skills/marketplace.js +142 -0
- package/dist/skills/types.d.ts +34 -0
- package/dist/skills/types.js +16 -0
- package/dist/studio/server.d.ts +25 -0
- package/dist/studio/server.js +780 -0
- package/dist/studio/templates-data.d.ts +21 -0
- package/dist/studio/templates-data.js +148 -0
- package/dist/studio-ui/index.html +2502 -1073
- package/dist/tools/builtin/browser.d.ts +47 -0
- package/dist/tools/builtin/browser.js +284 -0
- package/dist/tools/builtin/home-assistant.d.ts +12 -0
- package/dist/tools/builtin/home-assistant.js +126 -0
- package/dist/tools/builtin/index.d.ts +7 -1
- package/dist/tools/builtin/index.js +23 -2
- package/dist/tools/builtin/rl-tools.d.ts +13 -0
- package/dist/tools/builtin/rl-tools.js +228 -0
- package/dist/tools/builtin/vision.d.ts +6 -0
- package/dist/tools/builtin/vision.js +61 -0
- package/dist/tools/builtin/web-search.d.ts +9 -0
- package/dist/tools/builtin/web-search.js +150 -0
- package/dist/tools/document-processor.d.ts +39 -0
- package/dist/tools/document-processor.js +188 -0
- package/dist/tools/image-generator.d.ts +42 -0
- package/dist/tools/image-generator.js +136 -0
- package/dist/tools/web-scraper.d.ts +20 -0
- package/dist/tools/web-scraper.js +148 -0
- package/dist/tools/web-search.d.ts +51 -0
- package/dist/tools/web-search.js +152 -0
- package/install.ps1 +154 -0
- package/install.sh +164 -0
- package/package.json +63 -52
- package/src/channels/dingtalk.ts +46 -0
- package/src/channels/googlechat.ts +42 -0
- package/src/channels/imessage.ts +32 -0
- package/src/channels/irc.ts +82 -0
- package/src/channels/line.ts +33 -0
- package/src/channels/matrix.ts +34 -0
- package/src/channels/mattermost.ts +57 -0
- package/src/channels/msteams.ts +33 -0
- package/src/channels/nostr.ts +33 -0
- package/src/channels/qq.ts +34 -0
- package/src/channels/signal.ts +33 -0
- package/src/channels/sms.ts +34 -0
- package/src/channels/twitch.ts +65 -0
- package/src/channels/voice-call.ts +100 -0
- package/src/channels/whatsapp.ts +33 -0
- package/src/cli/chat.ts +99 -0
- package/src/cli/setup.ts +314 -0
- package/src/cli.ts +148 -6
- package/src/core/api-server.ts +277 -0
- package/src/core/audio.ts +98 -0
- package/src/core/context-discovery.ts +85 -0
- package/src/core/context-refs.ts +140 -0
- package/src/core/gateway.ts +106 -0
- package/src/core/heartbeat.ts +51 -0
- package/src/core/hooks.ts +105 -0
- package/src/core/ide-bridge.ts +133 -0
- package/src/core/node-network.ts +86 -0
- package/src/core/profiles.ts +122 -0
- package/src/core/sandbox.ts +100 -0
- package/src/core/session-manager.ts +137 -0
- package/src/core/vision.ts +180 -0
- package/src/hub/brain-seed.ts +54 -0
- package/src/hub/client.ts +60 -0
- package/src/index.ts +86 -1
- package/src/memory/context-compressor.ts +189 -0
- package/src/memory/index.ts +4 -0
- package/src/memory/user-profiler.ts +215 -0
- package/src/providers/index.ts +64 -1
- package/src/scheduler/cron-engine.ts +191 -0
- package/src/scheduler/index.ts +2 -0
- package/src/security/approvals.ts +143 -0
- package/src/security/elevated.ts +105 -0
- package/src/security/index.ts +6 -0
- package/src/security/secrets.ts +129 -0
- package/src/skills/builtin/index.ts +408 -0
- package/src/skills/marketplace.ts +113 -0
- package/src/skills/types.ts +42 -0
- package/src/studio/server.ts +1591 -791
- package/src/studio/templates-data.ts +178 -0
- package/src/studio-ui/index.html +2502 -1073
- package/src/tools/builtin/browser.ts +299 -0
- package/src/tools/builtin/home-assistant.ts +116 -0
- package/src/tools/builtin/index.ts +37 -28
- package/src/tools/builtin/rl-tools.ts +243 -0
- package/src/tools/builtin/vision.ts +64 -0
- package/src/tools/builtin/web-search.ts +126 -0
- package/src/tools/document-processor.ts +213 -0
- package/src/tools/image-generator.ts +150 -0
- package/src/tools/web-scraper.ts +179 -0
- package/src/tools/web-search.ts +180 -0
- package/tests/api-server.test.ts +148 -0
- package/tests/approvals.test.ts +89 -0
- package/tests/audio.test.ts +40 -0
- package/tests/browser.test.ts +179 -0
- package/tests/builtin-tools.test.ts +83 -83
- package/tests/channels-extra.test.ts +45 -0
- package/tests/context-compressor.test.ts +172 -0
- package/tests/context-refs.test.ts +121 -0
- package/tests/cron-engine.test.ts +101 -0
- package/tests/document-processor.test.ts +69 -0
- package/tests/e2e-nocode.test.ts +442 -0
- package/tests/elevated.test.ts +69 -0
- package/tests/gateway.test.ts +63 -71
- package/tests/home-assistant.test.ts +40 -0
- package/tests/hooks.test.ts +79 -0
- package/tests/ide-bridge.test.ts +38 -0
- package/tests/image-generator.test.ts +84 -0
- package/tests/node-network.test.ts +74 -0
- package/tests/profiles.test.ts +61 -0
- package/tests/rl-tools.test.ts +93 -0
- package/tests/sandbox-manager.test.ts +46 -0
- package/tests/secrets.test.ts +107 -0
- package/tests/settings-api.test.ts +148 -0
- package/tests/setup.test.ts +73 -0
- package/tests/studio.test.ts +402 -229
- package/tests/tools/builtin-extended.test.ts +138 -138
- package/tests/user-profiler.test.ts +169 -0
- package/tests/v090-features.test.ts +254 -0
- package/tests/vision.test.ts +61 -0
- package/tests/voice-call.test.ts +47 -0
- package/tests/voice-interaction.test.ts +38 -0
- package/tests/web-search.test.ts +155 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.APIServer = void 0;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const crypto_1 = require("crypto");
|
|
39
|
+
function jsonError(message, type, code) {
|
|
40
|
+
return { error: { message, type, code } };
|
|
41
|
+
}
|
|
42
|
+
function corsHeaders() {
|
|
43
|
+
return {
|
|
44
|
+
'Access-Control-Allow-Origin': '*',
|
|
45
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
46
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function parseBody(req) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const chunks = [];
|
|
52
|
+
req.on('data', (c) => chunks.push(c));
|
|
53
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
54
|
+
req.on('error', reject);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function sendJSON(res, status, data) {
|
|
58
|
+
const body = JSON.stringify(data);
|
|
59
|
+
res.writeHead(status, { ...corsHeaders(), 'Content-Type': 'application/json' });
|
|
60
|
+
res.end(body);
|
|
61
|
+
}
|
|
62
|
+
class APIServer {
|
|
63
|
+
server = null;
|
|
64
|
+
config;
|
|
65
|
+
constructor(config) {
|
|
66
|
+
this.config = {
|
|
67
|
+
port: config.port ?? 8080,
|
|
68
|
+
host: config.host ?? '0.0.0.0',
|
|
69
|
+
apiKey: config.apiKey,
|
|
70
|
+
agent: config.agent,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
authenticate(req) {
|
|
74
|
+
if (!this.config.apiKey)
|
|
75
|
+
return true;
|
|
76
|
+
const auth = req.headers['authorization'] ?? '';
|
|
77
|
+
return auth === `Bearer ${this.config.apiKey}`;
|
|
78
|
+
}
|
|
79
|
+
async start() {
|
|
80
|
+
return new Promise((resolve) => {
|
|
81
|
+
this.server = http.createServer((req, res) => this.handleRequest(req, res));
|
|
82
|
+
this.server.listen(this.config.port, this.config.host, () => resolve());
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async stop() {
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
if (this.server)
|
|
88
|
+
this.server.close(() => resolve());
|
|
89
|
+
else
|
|
90
|
+
resolve();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
getPort() { return this.config.port; }
|
|
94
|
+
getHost() { return this.config.host; }
|
|
95
|
+
async handleRequest(req, res) {
|
|
96
|
+
const url = req.url ?? '/';
|
|
97
|
+
const method = req.method ?? 'GET';
|
|
98
|
+
// CORS preflight
|
|
99
|
+
if (method === 'OPTIONS') {
|
|
100
|
+
res.writeHead(204, corsHeaders());
|
|
101
|
+
res.end();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Health check (no auth)
|
|
105
|
+
if (method === 'GET' && url === '/health') {
|
|
106
|
+
sendJSON(res, 200, { status: 'ok', timestamp: new Date().toISOString() });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Auth check for all other endpoints
|
|
110
|
+
if (!this.authenticate(req)) {
|
|
111
|
+
sendJSON(res, 401, jsonError('Invalid API key', 'authentication_error', 401));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
if (method === 'GET' && url === '/v1/models') {
|
|
116
|
+
return this.handleModels(res);
|
|
117
|
+
}
|
|
118
|
+
if (method === 'GET' && url === '/v1/agent/status') {
|
|
119
|
+
return this.handleAgentStatus(res);
|
|
120
|
+
}
|
|
121
|
+
if (method === 'POST' && url === '/v1/chat/completions') {
|
|
122
|
+
return await this.handleChatCompletions(req, res);
|
|
123
|
+
}
|
|
124
|
+
if (method === 'POST' && url === '/v1/embeddings') {
|
|
125
|
+
return await this.handleEmbeddings(req, res);
|
|
126
|
+
}
|
|
127
|
+
sendJSON(res, 404, jsonError('Not found', 'not_found', 404));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
+
sendJSON(res, 500, jsonError(msg, 'internal_error', 500));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
handleModels(res) {
|
|
135
|
+
const agent = this.config.agent;
|
|
136
|
+
const modelId = agent?.config?.model ?? agent?.model ?? 'default';
|
|
137
|
+
sendJSON(res, 200, {
|
|
138
|
+
object: 'list',
|
|
139
|
+
data: [{ id: modelId, object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'opc-agent' }],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
handleAgentStatus(res) {
|
|
143
|
+
const agent = this.config.agent;
|
|
144
|
+
sendJSON(res, 200, {
|
|
145
|
+
name: agent?.name ?? agent?.config?.name ?? 'unknown',
|
|
146
|
+
state: agent?.state ?? 'unknown',
|
|
147
|
+
uptime: process.uptime(),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
async handleChatCompletions(req, res) {
|
|
151
|
+
let body;
|
|
152
|
+
try {
|
|
153
|
+
body = JSON.parse(await parseBody(req));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
sendJSON(res, 400, jsonError('Invalid JSON body', 'invalid_request_error', 400));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const { model, messages, temperature, max_tokens, stream, tools } = body;
|
|
160
|
+
if (!messages || !Array.isArray(messages)) {
|
|
161
|
+
sendJSON(res, 400, jsonError('messages is required and must be an array', 'invalid_request_error', 400));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const agent = this.config.agent;
|
|
165
|
+
const requestId = `chatcmpl-${(0, crypto_1.randomUUID)().replace(/-/g, '').slice(0, 24)}`;
|
|
166
|
+
const modelId = model ?? agent?.config?.model ?? agent?.model ?? 'default';
|
|
167
|
+
if (stream) {
|
|
168
|
+
// SSE streaming
|
|
169
|
+
res.writeHead(200, {
|
|
170
|
+
...corsHeaders(),
|
|
171
|
+
'Content-Type': 'text/event-stream',
|
|
172
|
+
'Cache-Control': 'no-cache',
|
|
173
|
+
'Connection': 'keep-alive',
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
const responseText = await this.getAgentResponse(agent, messages, { temperature, max_tokens, tools });
|
|
177
|
+
// Stream in chunks
|
|
178
|
+
const chunkSize = 10;
|
|
179
|
+
for (let i = 0; i < responseText.length; i += chunkSize) {
|
|
180
|
+
const delta = responseText.slice(i, i + chunkSize);
|
|
181
|
+
const chunk = {
|
|
182
|
+
id: requestId,
|
|
183
|
+
object: 'chat.completion.chunk',
|
|
184
|
+
created: Math.floor(Date.now() / 1000),
|
|
185
|
+
model: modelId,
|
|
186
|
+
choices: [{ index: 0, delta: { content: delta }, finish_reason: null }],
|
|
187
|
+
};
|
|
188
|
+
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
189
|
+
}
|
|
190
|
+
// Final chunk
|
|
191
|
+
const finalChunk = {
|
|
192
|
+
id: requestId,
|
|
193
|
+
object: 'chat.completion.chunk',
|
|
194
|
+
created: Math.floor(Date.now() / 1000),
|
|
195
|
+
model: modelId,
|
|
196
|
+
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
|
|
197
|
+
};
|
|
198
|
+
res.write(`data: ${JSON.stringify(finalChunk)}\n\n`);
|
|
199
|
+
res.write('data: [DONE]\n\n');
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
203
|
+
res.write(`data: ${JSON.stringify({ error: { message: errMsg } })}\n\n`);
|
|
204
|
+
}
|
|
205
|
+
res.end();
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// Non-streaming
|
|
209
|
+
const responseText = await this.getAgentResponse(agent, messages, { temperature, max_tokens, tools });
|
|
210
|
+
sendJSON(res, 200, {
|
|
211
|
+
id: requestId,
|
|
212
|
+
object: 'chat.completion',
|
|
213
|
+
created: Math.floor(Date.now() / 1000),
|
|
214
|
+
model: modelId,
|
|
215
|
+
choices: [{
|
|
216
|
+
index: 0,
|
|
217
|
+
message: { role: 'assistant', content: responseText },
|
|
218
|
+
finish_reason: 'stop',
|
|
219
|
+
}],
|
|
220
|
+
usage: {
|
|
221
|
+
prompt_tokens: messages.reduce((a, m) => a + (m.content?.length ?? 0), 0),
|
|
222
|
+
completion_tokens: responseText.length,
|
|
223
|
+
total_tokens: messages.reduce((a, m) => a + (m.content?.length ?? 0), 0) + responseText.length,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async getAgentResponse(agent, messages, options) {
|
|
229
|
+
// Try various agent interfaces
|
|
230
|
+
if (agent?.chat) {
|
|
231
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === 'user');
|
|
232
|
+
return await agent.chat(lastUserMsg?.content ?? '', options);
|
|
233
|
+
}
|
|
234
|
+
if (agent?.processMessage) {
|
|
235
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === 'user');
|
|
236
|
+
const result = await agent.processMessage({ id: 'api', role: 'user', content: lastUserMsg?.content ?? '', timestamp: Date.now() });
|
|
237
|
+
return result?.response ?? result?.content ?? String(result);
|
|
238
|
+
}
|
|
239
|
+
if (agent?.provider?.chat) {
|
|
240
|
+
const formatted = messages.map((m) => ({ id: 'x', role: m.role, content: m.content, timestamp: Date.now() }));
|
|
241
|
+
return await agent.provider.chat(formatted, agent.systemPrompt ?? '');
|
|
242
|
+
}
|
|
243
|
+
return 'Agent does not support chat interface';
|
|
244
|
+
}
|
|
245
|
+
async handleEmbeddings(req, res) {
|
|
246
|
+
let body;
|
|
247
|
+
try {
|
|
248
|
+
body = JSON.parse(await parseBody(req));
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
sendJSON(res, 400, jsonError('Invalid JSON body', 'invalid_request_error', 400));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const { input, model } = body;
|
|
255
|
+
if (!input) {
|
|
256
|
+
sendJSON(res, 400, jsonError('input is required', 'invalid_request_error', 400));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const agent = this.config.agent;
|
|
260
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
261
|
+
try {
|
|
262
|
+
if (agent?.embed || agent?.provider?.embed) {
|
|
263
|
+
const embedFn = agent.embed?.bind(agent) ?? agent.provider.embed.bind(agent.provider);
|
|
264
|
+
const data = await Promise.all(inputs.map(async (text, i) => {
|
|
265
|
+
const embedding = await embedFn(text);
|
|
266
|
+
return { object: 'embedding', embedding, index: i };
|
|
267
|
+
}));
|
|
268
|
+
sendJSON(res, 200, {
|
|
269
|
+
object: 'list',
|
|
270
|
+
data,
|
|
271
|
+
model: model ?? 'default',
|
|
272
|
+
usage: { prompt_tokens: inputs.join('').length, total_tokens: inputs.join('').length },
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
sendJSON(res, 501, jsonError('Embedding provider not configured', 'not_implemented', 501));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
281
|
+
sendJSON(res, 500, jsonError(msg, 'internal_error', 500));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
exports.APIServer = APIServer;
|
|
286
|
+
//# sourceMappingURL=api-server.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio Processor - v1.0.0
|
|
3
|
+
* Audio transcription/synthesis wrappers with format detection, duration, split.
|
|
4
|
+
*/
|
|
5
|
+
export type AudioFormat = 'wav' | 'mp3' | 'ogg' | 'flac' | 'webm' | 'aac' | 'unknown';
|
|
6
|
+
export interface TranscribeOptions {
|
|
7
|
+
language?: string;
|
|
8
|
+
model?: string;
|
|
9
|
+
provider?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SynthesizeOptions {
|
|
12
|
+
voice?: string;
|
|
13
|
+
speed?: number;
|
|
14
|
+
format?: AudioFormat;
|
|
15
|
+
provider?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TranscribeResult {
|
|
18
|
+
text: string;
|
|
19
|
+
language?: string;
|
|
20
|
+
duration?: number;
|
|
21
|
+
segments?: {
|
|
22
|
+
start: number;
|
|
23
|
+
end: number;
|
|
24
|
+
text: string;
|
|
25
|
+
}[];
|
|
26
|
+
}
|
|
27
|
+
export interface SynthesizeResult {
|
|
28
|
+
audio: Buffer;
|
|
29
|
+
format: AudioFormat;
|
|
30
|
+
duration?: number;
|
|
31
|
+
}
|
|
32
|
+
export type TranscribeFunction = (audio: Buffer, options?: TranscribeOptions) => Promise<TranscribeResult>;
|
|
33
|
+
export type SynthesizeFunction = (text: string, options?: SynthesizeOptions) => Promise<SynthesizeResult>;
|
|
34
|
+
export declare class AudioProcessor {
|
|
35
|
+
private transcribeFn?;
|
|
36
|
+
private synthesizeFn?;
|
|
37
|
+
constructor(options?: {
|
|
38
|
+
transcribe?: TranscribeFunction;
|
|
39
|
+
synthesize?: SynthesizeFunction;
|
|
40
|
+
});
|
|
41
|
+
/** Detect audio format from buffer header */
|
|
42
|
+
static detectFormat(audio: Buffer): AudioFormat;
|
|
43
|
+
/** Estimate duration in seconds for WAV files (for others returns undefined) */
|
|
44
|
+
static estimateDuration(audio: Buffer): number | undefined;
|
|
45
|
+
/** Split audio buffer into chunks of roughly `chunkBytes` size */
|
|
46
|
+
static split(audio: Buffer, chunkBytes: number): Buffer[];
|
|
47
|
+
transcribe(audio: Buffer, options?: TranscribeOptions): Promise<TranscribeResult>;
|
|
48
|
+
synthesize(text: string, options?: SynthesizeOptions): Promise<SynthesizeResult>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audio Processor - v1.0.0
|
|
4
|
+
* Audio transcription/synthesis wrappers with format detection, duration, split.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.AudioProcessor = void 0;
|
|
8
|
+
const FORMAT_SIGNATURES = [
|
|
9
|
+
[Buffer.from('RIFF'), 'wav'],
|
|
10
|
+
[Buffer.from([0xff, 0xfb]), 'mp3'],
|
|
11
|
+
[Buffer.from([0xff, 0xf3]), 'mp3'],
|
|
12
|
+
[Buffer.from([0xff, 0xf2]), 'mp3'],
|
|
13
|
+
[Buffer.from([0x49, 0x44, 0x33]), 'mp3'], // ID3
|
|
14
|
+
[Buffer.from('OggS'), 'ogg'],
|
|
15
|
+
[Buffer.from('fLaC'), 'flac'],
|
|
16
|
+
[Buffer.from([0x1a, 0x45, 0xdf, 0xa3]), 'webm'],
|
|
17
|
+
];
|
|
18
|
+
class AudioProcessor {
|
|
19
|
+
transcribeFn;
|
|
20
|
+
synthesizeFn;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.transcribeFn = options?.transcribe;
|
|
23
|
+
this.synthesizeFn = options?.synthesize;
|
|
24
|
+
}
|
|
25
|
+
/** Detect audio format from buffer header */
|
|
26
|
+
static detectFormat(audio) {
|
|
27
|
+
for (const [sig, fmt] of FORMAT_SIGNATURES) {
|
|
28
|
+
if (audio.length >= sig.length && audio.subarray(0, sig.length).equals(sig))
|
|
29
|
+
return fmt;
|
|
30
|
+
}
|
|
31
|
+
return 'unknown';
|
|
32
|
+
}
|
|
33
|
+
/** Estimate duration in seconds for WAV files (for others returns undefined) */
|
|
34
|
+
static estimateDuration(audio) {
|
|
35
|
+
const fmt = AudioProcessor.detectFormat(audio);
|
|
36
|
+
if (fmt === 'wav' && audio.length >= 44) {
|
|
37
|
+
const sampleRate = audio.readUInt32LE(24);
|
|
38
|
+
const byteRate = audio.readUInt32LE(28);
|
|
39
|
+
if (byteRate > 0) {
|
|
40
|
+
const dataSize = audio.length - 44;
|
|
41
|
+
return dataSize / byteRate;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Split audio buffer into chunks of roughly `chunkBytes` size */
|
|
47
|
+
static split(audio, chunkBytes) {
|
|
48
|
+
if (chunkBytes <= 0)
|
|
49
|
+
throw new Error('chunkBytes must be positive');
|
|
50
|
+
const chunks = [];
|
|
51
|
+
for (let i = 0; i < audio.length; i += chunkBytes) {
|
|
52
|
+
chunks.push(audio.subarray(i, Math.min(i + chunkBytes, audio.length)));
|
|
53
|
+
}
|
|
54
|
+
return chunks;
|
|
55
|
+
}
|
|
56
|
+
async transcribe(audio, options) {
|
|
57
|
+
if (!this.transcribeFn)
|
|
58
|
+
throw new Error('No transcribe provider configured');
|
|
59
|
+
return this.transcribeFn(audio, options);
|
|
60
|
+
}
|
|
61
|
+
async synthesize(text, options) {
|
|
62
|
+
if (!this.synthesizeFn)
|
|
63
|
+
throw new Error('No synthesize provider configured');
|
|
64
|
+
return this.synthesizeFn(text, options);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.AudioProcessor = AudioProcessor;
|
|
68
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ContextFile {
|
|
2
|
+
path: string;
|
|
3
|
+
type: 'agents' | 'soul' | 'user' | 'memory' | 'tools' | 'identity' | 'heartbeat' | 'bootstrap' | 'custom';
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ContextDiscovery {
|
|
7
|
+
static STANDARD_FILES: string[];
|
|
8
|
+
private customFiles;
|
|
9
|
+
private watchers;
|
|
10
|
+
discover(workDir?: string): ContextFile[];
|
|
11
|
+
load(files: ContextFile[]): string;
|
|
12
|
+
watch(workDir: string, onChange: Function): void;
|
|
13
|
+
stopWatching(): void;
|
|
14
|
+
addCustomFile(filePath: string): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=context-discovery.d.ts.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ContextDiscovery = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const FILE_TYPE_MAP = {
|
|
40
|
+
'AGENTS.md': 'agents',
|
|
41
|
+
'SOUL.md': 'soul',
|
|
42
|
+
'USER.md': 'user',
|
|
43
|
+
'MEMORY.md': 'memory',
|
|
44
|
+
'TOOLS.md': 'tools',
|
|
45
|
+
'IDENTITY.md': 'identity',
|
|
46
|
+
'HEARTBEAT.md': 'heartbeat',
|
|
47
|
+
'BOOTSTRAP.md': 'bootstrap',
|
|
48
|
+
'.opc.md': 'custom',
|
|
49
|
+
'.opc/config.md': 'custom',
|
|
50
|
+
};
|
|
51
|
+
class ContextDiscovery {
|
|
52
|
+
static STANDARD_FILES = [
|
|
53
|
+
'AGENTS.md', 'SOUL.md', 'USER.md', 'MEMORY.md', 'TOOLS.md',
|
|
54
|
+
'IDENTITY.md', 'HEARTBEAT.md', 'BOOTSTRAP.md',
|
|
55
|
+
'.opc.md', '.opc/config.md',
|
|
56
|
+
];
|
|
57
|
+
customFiles = [];
|
|
58
|
+
watchers = [];
|
|
59
|
+
discover(workDir) {
|
|
60
|
+
const dir = workDir || process.cwd();
|
|
61
|
+
const found = [];
|
|
62
|
+
for (const file of ContextDiscovery.STANDARD_FILES) {
|
|
63
|
+
const fullPath = path.join(dir, file);
|
|
64
|
+
if (fs.existsSync(fullPath)) {
|
|
65
|
+
found.push({
|
|
66
|
+
path: fullPath,
|
|
67
|
+
type: FILE_TYPE_MAP[file] || 'custom',
|
|
68
|
+
content: fs.readFileSync(fullPath, 'utf-8'),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const file of this.customFiles) {
|
|
73
|
+
const fullPath = path.isAbsolute(file) ? file : path.join(dir, file);
|
|
74
|
+
if (fs.existsSync(fullPath)) {
|
|
75
|
+
found.push({
|
|
76
|
+
path: fullPath,
|
|
77
|
+
type: 'custom',
|
|
78
|
+
content: fs.readFileSync(fullPath, 'utf-8'),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return found;
|
|
83
|
+
}
|
|
84
|
+
load(files) {
|
|
85
|
+
return files.map(f => `# ${f.type.toUpperCase()}\n${f.content}`).join('\n\n');
|
|
86
|
+
}
|
|
87
|
+
watch(workDir, onChange) {
|
|
88
|
+
const watcher = fs.watch(workDir, { recursive: false }, (event, filename) => {
|
|
89
|
+
if (filename && ContextDiscovery.STANDARD_FILES.includes(filename)) {
|
|
90
|
+
onChange(filename, event);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
this.watchers.push(watcher);
|
|
94
|
+
}
|
|
95
|
+
stopWatching() {
|
|
96
|
+
for (const w of this.watchers)
|
|
97
|
+
w.close();
|
|
98
|
+
this.watchers = [];
|
|
99
|
+
}
|
|
100
|
+
addCustomFile(filePath) {
|
|
101
|
+
if (!this.customFiles.includes(filePath)) {
|
|
102
|
+
this.customFiles.push(filePath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.ContextDiscovery = ContextDiscovery;
|
|
107
|
+
//# sourceMappingURL=context-discovery.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type RefType = 'file' | 'folder' | 'url' | 'git-diff' | 'git-log';
|
|
2
|
+
export interface ContextRef {
|
|
3
|
+
type: RefType;
|
|
4
|
+
path: string;
|
|
5
|
+
content?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Message {
|
|
8
|
+
role: string;
|
|
9
|
+
content: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare class ContextRefResolver {
|
|
13
|
+
/**
|
|
14
|
+
* Parse @-references from text without resolving content.
|
|
15
|
+
*/
|
|
16
|
+
parseRefs(text: string): ContextRef[];
|
|
17
|
+
/**
|
|
18
|
+
* Resolve content for each ref. Returns new array with content filled in.
|
|
19
|
+
*/
|
|
20
|
+
resolveRefs(refs: ContextRef[]): Promise<ContextRef[]>;
|
|
21
|
+
private resolveOne;
|
|
22
|
+
private listDir;
|
|
23
|
+
private fetchUrl;
|
|
24
|
+
/**
|
|
25
|
+
* Inject resolved refs as system messages before the user's last message.
|
|
26
|
+
*/
|
|
27
|
+
injectRefs(messages: Message[], refs: ContextRef[]): Message[];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=context-refs.d.ts.map
|