opc-agent 3.0.0 → 4.0.0
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 +30 -24
- 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.js +36 -0
- 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/index.d.ts +64 -1
- package/dist/index.js +86 -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/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/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 +6 -1
- package/dist/tools/builtin/index.js +18 -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/package.json +3 -3
- 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.ts +40 -0
- 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/index.ts +84 -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/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/tools/builtin/browser.ts +299 -0
- package/src/tools/builtin/home-assistant.ts +116 -0
- package/src/tools/builtin/index.ts +9 -2
- package/src/tools/builtin/rl-tools.ts +243 -0
- package/src/tools/builtin/vision.ts +64 -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/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/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/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
|
@@ -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
|
|
@@ -0,0 +1,162 @@
|
|
|
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.ContextRefResolver = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const MAX_CONTENT_LENGTH = 5000;
|
|
41
|
+
function truncate(text, max = MAX_CONTENT_LENGTH) {
|
|
42
|
+
if (text.length <= max)
|
|
43
|
+
return text;
|
|
44
|
+
return text.slice(0, max) + `\n...[truncated, ${text.length - max} chars omitted]`;
|
|
45
|
+
}
|
|
46
|
+
class ContextRefResolver {
|
|
47
|
+
/**
|
|
48
|
+
* Parse @-references from text without resolving content.
|
|
49
|
+
*/
|
|
50
|
+
parseRefs(text) {
|
|
51
|
+
const refs = [];
|
|
52
|
+
const patterns = [
|
|
53
|
+
[/@file:(\S+)/g, 'file', (m) => m[1]],
|
|
54
|
+
[/@folder:(\S+)/g, 'folder', (m) => m[1]],
|
|
55
|
+
[/@url:(https?:\/\/\S+)/g, 'url', (m) => m[1]],
|
|
56
|
+
[/@git-diff\b/g, 'git-diff', () => 'git-diff'],
|
|
57
|
+
[/@git-log:(\d+)/g, 'git-log', (m) => m[1]],
|
|
58
|
+
[/@git-log\b(?!:)/g, 'git-log', () => '10'],
|
|
59
|
+
];
|
|
60
|
+
for (const [regex, type, extract] of patterns) {
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = regex.exec(text)) !== null) {
|
|
63
|
+
refs.push({ type, path: extract(match) });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return refs;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Resolve content for each ref. Returns new array with content filled in.
|
|
70
|
+
*/
|
|
71
|
+
async resolveRefs(refs) {
|
|
72
|
+
return Promise.all(refs.map(async (ref) => {
|
|
73
|
+
try {
|
|
74
|
+
const content = await this.resolveOne(ref);
|
|
75
|
+
return { ...ref, content: truncate(content) };
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
+
return { ...ref, content: `[Error resolving @${ref.type}:${ref.path}]: ${msg}` };
|
|
80
|
+
}
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
async resolveOne(ref) {
|
|
84
|
+
switch (ref.type) {
|
|
85
|
+
case 'file':
|
|
86
|
+
return fs.readFileSync(ref.path, 'utf-8');
|
|
87
|
+
case 'folder':
|
|
88
|
+
return this.listDir(ref.path);
|
|
89
|
+
case 'url':
|
|
90
|
+
return await this.fetchUrl(ref.path);
|
|
91
|
+
case 'git-diff':
|
|
92
|
+
return (0, child_process_1.execSync)('git diff', { encoding: 'utf-8', timeout: 10000 });
|
|
93
|
+
case 'git-log': {
|
|
94
|
+
const n = parseInt(ref.path) || 10;
|
|
95
|
+
return (0, child_process_1.execSync)(`git log --oneline -${n}`, { encoding: 'utf-8', timeout: 10000 });
|
|
96
|
+
}
|
|
97
|
+
default:
|
|
98
|
+
return `[Unknown ref type: ${ref.type}]`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
listDir(dirPath, prefix = '', depth = 0) {
|
|
102
|
+
if (depth > 5)
|
|
103
|
+
return prefix + '...(max depth)\n';
|
|
104
|
+
if (!fs.existsSync(dirPath))
|
|
105
|
+
throw new Error(`Directory not found: ${dirPath}`);
|
|
106
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
107
|
+
let result = '';
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
110
|
+
continue;
|
|
111
|
+
result += `${prefix}${entry.isDirectory() ? '📁 ' : '📄 '}${entry.name}\n`;
|
|
112
|
+
if (entry.isDirectory()) {
|
|
113
|
+
result += this.listDir(path.join(dirPath, entry.name), prefix + ' ', depth + 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
async fetchUrl(url) {
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
121
|
+
try {
|
|
122
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
123
|
+
const text = await res.text();
|
|
124
|
+
return text;
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
clearTimeout(timeout);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Inject resolved refs as system messages before the user's last message.
|
|
132
|
+
*/
|
|
133
|
+
injectRefs(messages, refs) {
|
|
134
|
+
if (refs.length === 0)
|
|
135
|
+
return messages;
|
|
136
|
+
const resolvedRefs = refs.filter(r => r.content);
|
|
137
|
+
if (resolvedRefs.length === 0)
|
|
138
|
+
return messages;
|
|
139
|
+
const contextMessages = resolvedRefs.map(ref => ({
|
|
140
|
+
role: 'system',
|
|
141
|
+
content: `[Context from @${ref.type}:${ref.path}]\n\`\`\`\n${ref.content}\n\`\`\``,
|
|
142
|
+
}));
|
|
143
|
+
// Insert before the last user message
|
|
144
|
+
const result = [...messages];
|
|
145
|
+
let lastUserIdx = -1;
|
|
146
|
+
for (let i = result.length - 1; i >= 0; i--) {
|
|
147
|
+
if (result[i].role === 'user') {
|
|
148
|
+
lastUserIdx = i;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (lastUserIdx >= 0) {
|
|
153
|
+
result.splice(lastUserIdx, 0, ...contextMessages);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
result.push(...contextMessages);
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.ContextRefResolver = ContextRefResolver;
|
|
162
|
+
//# sourceMappingURL=context-refs.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export interface AgentConfig {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
skills?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface ChannelConfig {
|
|
9
|
+
id: string;
|
|
10
|
+
type: string;
|
|
11
|
+
config?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
export interface GatewayConfig {
|
|
14
|
+
port: number;
|
|
15
|
+
agents: AgentConfig[];
|
|
16
|
+
channels: ChannelConfig[];
|
|
17
|
+
}
|
|
18
|
+
interface GatewayMessage {
|
|
19
|
+
id: string;
|
|
20
|
+
content: string;
|
|
21
|
+
channel: string;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class Gateway extends EventEmitter {
|
|
25
|
+
private config;
|
|
26
|
+
private agents;
|
|
27
|
+
private channels;
|
|
28
|
+
private running;
|
|
29
|
+
private startTime;
|
|
30
|
+
private messagesProcessed;
|
|
31
|
+
private latencies;
|
|
32
|
+
private errors;
|
|
33
|
+
constructor(config: GatewayConfig);
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
routeMessage(message: GatewayMessage, channel: string): Promise<string>;
|
|
37
|
+
addAgent(config: AgentConfig): void;
|
|
38
|
+
removeAgent(id: string): void;
|
|
39
|
+
addChannel(config: ChannelConfig): void;
|
|
40
|
+
getStatus(): {
|
|
41
|
+
uptime: number;
|
|
42
|
+
agents: number;
|
|
43
|
+
channels: number;
|
|
44
|
+
messagesProcessed: number;
|
|
45
|
+
};
|
|
46
|
+
getMetrics(): {
|
|
47
|
+
messagesPerMinute: number;
|
|
48
|
+
avgLatency: number;
|
|
49
|
+
errorRate: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=gateway.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gateway = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
class Gateway extends events_1.EventEmitter {
|
|
6
|
+
config;
|
|
7
|
+
agents = new Map();
|
|
8
|
+
channels = new Map();
|
|
9
|
+
running = false;
|
|
10
|
+
startTime = 0;
|
|
11
|
+
messagesProcessed = 0;
|
|
12
|
+
latencies = [];
|
|
13
|
+
errors = 0;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
super();
|
|
16
|
+
this.config = config;
|
|
17
|
+
for (const a of config.agents)
|
|
18
|
+
this.agents.set(a.id, a);
|
|
19
|
+
for (const c of config.channels)
|
|
20
|
+
this.channels.set(c.id, c);
|
|
21
|
+
}
|
|
22
|
+
async start() {
|
|
23
|
+
if (this.running)
|
|
24
|
+
throw new Error('Gateway already running');
|
|
25
|
+
this.running = true;
|
|
26
|
+
this.startTime = Date.now();
|
|
27
|
+
this.emit('started');
|
|
28
|
+
}
|
|
29
|
+
async stop() {
|
|
30
|
+
if (!this.running)
|
|
31
|
+
throw new Error('Gateway not running');
|
|
32
|
+
this.running = false;
|
|
33
|
+
this.emit('stopped');
|
|
34
|
+
}
|
|
35
|
+
async routeMessage(message, channel) {
|
|
36
|
+
if (!this.running)
|
|
37
|
+
throw new Error('Gateway not running');
|
|
38
|
+
const start = Date.now();
|
|
39
|
+
this.messagesProcessed++;
|
|
40
|
+
// Simple round-robin routing
|
|
41
|
+
const agentIds = Array.from(this.agents.keys());
|
|
42
|
+
if (agentIds.length === 0) {
|
|
43
|
+
this.errors++;
|
|
44
|
+
throw new Error('No agents available');
|
|
45
|
+
}
|
|
46
|
+
const agentId = agentIds[this.messagesProcessed % agentIds.length];
|
|
47
|
+
this.latencies.push(Date.now() - start);
|
|
48
|
+
return agentId;
|
|
49
|
+
}
|
|
50
|
+
addAgent(config) {
|
|
51
|
+
this.agents.set(config.id, config);
|
|
52
|
+
}
|
|
53
|
+
removeAgent(id) {
|
|
54
|
+
if (!this.agents.has(id))
|
|
55
|
+
throw new Error(`Agent ${id} not found`);
|
|
56
|
+
this.agents.delete(id);
|
|
57
|
+
}
|
|
58
|
+
addChannel(config) {
|
|
59
|
+
this.channels.set(config.id, config);
|
|
60
|
+
}
|
|
61
|
+
getStatus() {
|
|
62
|
+
return {
|
|
63
|
+
uptime: this.running ? Date.now() - this.startTime : 0,
|
|
64
|
+
agents: this.agents.size,
|
|
65
|
+
channels: this.channels.size,
|
|
66
|
+
messagesProcessed: this.messagesProcessed,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
getMetrics() {
|
|
70
|
+
const upMinutes = this.running ? (Date.now() - this.startTime) / 60000 : 1;
|
|
71
|
+
const avgLatency = this.latencies.length ? this.latencies.reduce((a, b) => a + b, 0) / this.latencies.length : 0;
|
|
72
|
+
return {
|
|
73
|
+
messagesPerMinute: this.messagesProcessed / Math.max(upMinutes, 0.001),
|
|
74
|
+
avgLatency,
|
|
75
|
+
errorRate: this.messagesProcessed ? this.errors / this.messagesProcessed : 0,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.Gateway = Gateway;
|
|
80
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface HeartbeatConfig {
|
|
2
|
+
interval: number;
|
|
3
|
+
checkFn: () => Promise<string>;
|
|
4
|
+
}
|
|
5
|
+
export declare class HeartbeatManager {
|
|
6
|
+
private config;
|
|
7
|
+
private timer;
|
|
8
|
+
private callbacks;
|
|
9
|
+
private lastBeat;
|
|
10
|
+
constructor(config: HeartbeatConfig);
|
|
11
|
+
start(): void;
|
|
12
|
+
stop(): void;
|
|
13
|
+
onBeat(callback: (status: string) => void): void;
|
|
14
|
+
getLastBeat(): {
|
|
15
|
+
timestamp: number;
|
|
16
|
+
status: string;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HeartbeatManager = void 0;
|
|
4
|
+
class HeartbeatManager {
|
|
5
|
+
config;
|
|
6
|
+
timer = null;
|
|
7
|
+
callbacks = [];
|
|
8
|
+
lastBeat = null;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
if (!config.interval || config.interval < 100) {
|
|
11
|
+
throw new Error('HeartbeatManager requires interval >= 100ms');
|
|
12
|
+
}
|
|
13
|
+
if (typeof config.checkFn !== 'function') {
|
|
14
|
+
throw new Error('HeartbeatManager requires checkFn');
|
|
15
|
+
}
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
start() {
|
|
19
|
+
if (this.timer)
|
|
20
|
+
return;
|
|
21
|
+
this.timer = setInterval(async () => {
|
|
22
|
+
try {
|
|
23
|
+
const status = await this.config.checkFn();
|
|
24
|
+
this.lastBeat = { timestamp: Date.now(), status };
|
|
25
|
+
for (const cb of this.callbacks)
|
|
26
|
+
cb(status);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const status = `error: ${err.message}`;
|
|
30
|
+
this.lastBeat = { timestamp: Date.now(), status };
|
|
31
|
+
for (const cb of this.callbacks)
|
|
32
|
+
cb(status);
|
|
33
|
+
}
|
|
34
|
+
}, this.config.interval);
|
|
35
|
+
}
|
|
36
|
+
stop() {
|
|
37
|
+
if (this.timer) {
|
|
38
|
+
clearInterval(this.timer);
|
|
39
|
+
this.timer = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
onBeat(callback) {
|
|
43
|
+
this.callbacks.push(callback);
|
|
44
|
+
}
|
|
45
|
+
getLastBeat() {
|
|
46
|
+
return this.lastBeat;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.HeartbeatManager = HeartbeatManager;
|
|
50
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Module - v1.0.0
|
|
3
|
+
* Event hook system with priority ordering and context modification.
|
|
4
|
+
*/
|
|
5
|
+
export type HookEvent = 'before:message' | 'after:message' | 'before:tool' | 'after:tool' | 'before:llm' | 'after:llm' | 'before:send' | 'after:send' | 'before:learn' | 'after:learn' | 'before:recall' | 'after:recall' | 'on:error' | 'on:start' | 'on:stop';
|
|
6
|
+
export declare const ALL_HOOK_EVENTS: HookEvent[];
|
|
7
|
+
export interface HookContext {
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export type HookHandler = (ctx: HookContext) => HookContext | void | Promise<HookContext | void>;
|
|
11
|
+
export declare class HookManager {
|
|
12
|
+
private hooks;
|
|
13
|
+
register(event: HookEvent, handler: HookHandler, options?: {
|
|
14
|
+
priority?: number;
|
|
15
|
+
name?: string;
|
|
16
|
+
}): string;
|
|
17
|
+
unregister(id: string): boolean;
|
|
18
|
+
run(event: HookEvent, ctx?: HookContext): Promise<HookContext>;
|
|
19
|
+
getRegistered(event?: HookEvent): {
|
|
20
|
+
id: string;
|
|
21
|
+
event: HookEvent;
|
|
22
|
+
priority: number;
|
|
23
|
+
name?: string;
|
|
24
|
+
}[];
|
|
25
|
+
clear(event?: HookEvent): void;
|
|
26
|
+
hasHooks(event: HookEvent): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=hooks.d.ts.map
|