opc-agent 0.2.0 → 0.4.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/dist/analytics/index.d.ts +31 -0
- package/dist/analytics/index.js +52 -0
- package/dist/channels/voice.d.ts +43 -0
- package/dist/channels/voice.js +67 -0
- package/dist/channels/webhook.d.ts +40 -0
- package/dist/channels/webhook.js +193 -0
- package/dist/cli.js +157 -13
- package/dist/core/a2a.d.ts +46 -0
- package/dist/core/a2a.js +99 -0
- package/dist/core/hitl.d.ts +41 -0
- package/dist/core/hitl.js +100 -0
- package/dist/core/performance.d.ts +50 -0
- package/dist/core/performance.js +148 -0
- package/dist/core/room.d.ts +24 -0
- package/dist/core/room.js +97 -0
- package/dist/core/sandbox.d.ts +28 -0
- package/dist/core/sandbox.js +118 -0
- package/dist/core/versioning.d.ts +29 -0
- package/dist/core/versioning.js +114 -0
- package/dist/core/workflow.d.ts +59 -0
- package/dist/core/workflow.js +174 -0
- package/dist/i18n/index.d.ts +13 -0
- package/dist/i18n/index.js +73 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +36 -1
- package/dist/plugins/index.d.ts +47 -0
- package/dist/plugins/index.js +59 -0
- package/dist/schema/oad.d.ts +483 -15
- package/dist/schema/oad.js +53 -2
- package/dist/templates/content-writer.d.ts +36 -0
- package/dist/templates/content-writer.js +52 -0
- package/dist/templates/executive-assistant.d.ts +20 -0
- package/dist/templates/executive-assistant.js +70 -0
- package/dist/templates/financial-advisor.d.ts +15 -0
- package/dist/templates/financial-advisor.js +60 -0
- package/dist/templates/hr-recruiter.d.ts +36 -0
- package/dist/templates/hr-recruiter.js +52 -0
- package/dist/templates/legal-assistant.d.ts +15 -0
- package/dist/templates/legal-assistant.js +70 -0
- package/dist/templates/project-manager.d.ts +36 -0
- package/dist/templates/project-manager.js +52 -0
- package/dist/tools/mcp.d.ts +32 -0
- package/dist/tools/mcp.js +49 -0
- package/package.json +46 -46
- package/src/analytics/index.ts +66 -0
- package/src/channels/voice.ts +106 -0
- package/src/channels/webhook.ts +199 -0
- package/src/cli.ts +173 -16
- package/src/core/a2a.ts +143 -0
- package/src/core/hitl.ts +138 -0
- package/src/core/performance.ts +187 -0
- package/src/core/room.ts +109 -0
- package/src/core/sandbox.ts +101 -0
- package/src/core/versioning.ts +106 -0
- package/src/core/workflow.ts +235 -0
- package/src/i18n/index.ts +79 -0
- package/src/index.ts +29 -0
- package/src/plugins/index.ts +87 -0
- package/src/schema/oad.ts +59 -1
- package/src/templates/content-writer.ts +58 -0
- package/src/templates/executive-assistant.ts +71 -0
- package/src/templates/financial-advisor.ts +60 -0
- package/src/templates/hr-recruiter.ts +58 -0
- package/src/templates/legal-assistant.ts +71 -0
- package/src/templates/project-manager.ts +58 -0
- package/src/tools/mcp.ts +76 -0
- package/tests/a2a.test.ts +66 -0
- package/tests/analytics.test.ts +50 -0
- package/tests/hitl.test.ts +71 -0
- package/tests/i18n.test.ts +41 -0
- package/tests/mcp.test.ts +54 -0
- package/tests/performance.test.ts +115 -0
- package/tests/plugin.test.ts +74 -0
- package/tests/room.test.ts +106 -0
- package/tests/sandbox.test.ts +46 -0
- package/tests/templates.test.ts +77 -0
- package/tests/versioning.test.ts +75 -0
- package/tests/voice.test.ts +61 -0
- package/tests/webhook.test.ts +29 -0
- package/tests/workflow.test.ts +143 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Room } from './room';
|
|
3
|
+
import type { IAgent } from './types';
|
|
4
|
+
export interface AgentCapability {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema?: Record<string, unknown>;
|
|
8
|
+
outputSchema?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentRegistration {
|
|
11
|
+
agentName: string;
|
|
12
|
+
capabilities: AgentCapability[];
|
|
13
|
+
endpoint?: string;
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface A2ARequest {
|
|
17
|
+
id: string;
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
capability: string;
|
|
21
|
+
payload: string;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface A2AResponse {
|
|
26
|
+
requestId: string;
|
|
27
|
+
from: string;
|
|
28
|
+
status: 'success' | 'error' | 'timeout';
|
|
29
|
+
payload?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
export declare class AgentRegistry extends EventEmitter {
|
|
34
|
+
private registrations;
|
|
35
|
+
private agents;
|
|
36
|
+
private room;
|
|
37
|
+
private logger;
|
|
38
|
+
constructor(room?: Room);
|
|
39
|
+
register(agent: IAgent, capabilities: AgentCapability[]): void;
|
|
40
|
+
unregister(name: string): void;
|
|
41
|
+
discover(capability?: string): AgentRegistration[];
|
|
42
|
+
getAgent(name: string): IAgent | undefined;
|
|
43
|
+
request(req: A2ARequest): Promise<A2AResponse>;
|
|
44
|
+
call(from: string, to: string, capability: string, payload: string): Promise<A2AResponse>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=a2a.d.ts.map
|
package/dist/core/a2a.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentRegistry = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const room_1 = require("./room");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
// ── Agent Registry ──────────────────────────────────────────
|
|
8
|
+
class AgentRegistry extends events_1.EventEmitter {
|
|
9
|
+
registrations = new Map();
|
|
10
|
+
agents = new Map();
|
|
11
|
+
room;
|
|
12
|
+
logger = new logger_1.Logger('a2a');
|
|
13
|
+
constructor(room) {
|
|
14
|
+
super();
|
|
15
|
+
this.room = room ?? new room_1.Room('a2a-default');
|
|
16
|
+
}
|
|
17
|
+
register(agent, capabilities) {
|
|
18
|
+
const reg = { agentName: agent.name, capabilities };
|
|
19
|
+
this.registrations.set(agent.name, reg);
|
|
20
|
+
this.agents.set(agent.name, agent);
|
|
21
|
+
this.room.addAgent(agent);
|
|
22
|
+
this.logger.info('Agent registered', { name: agent.name, capabilities: capabilities.map(c => c.name) });
|
|
23
|
+
this.emit('agent:registered', reg);
|
|
24
|
+
}
|
|
25
|
+
unregister(name) {
|
|
26
|
+
this.registrations.delete(name);
|
|
27
|
+
this.agents.delete(name);
|
|
28
|
+
this.room.removeAgent(name);
|
|
29
|
+
this.emit('agent:unregistered', name);
|
|
30
|
+
}
|
|
31
|
+
discover(capability) {
|
|
32
|
+
const all = Array.from(this.registrations.values());
|
|
33
|
+
if (!capability)
|
|
34
|
+
return all;
|
|
35
|
+
return all.filter(r => r.capabilities.some(c => c.name === capability));
|
|
36
|
+
}
|
|
37
|
+
getAgent(name) {
|
|
38
|
+
return this.agents.get(name);
|
|
39
|
+
}
|
|
40
|
+
async request(req) {
|
|
41
|
+
const agent = this.agents.get(req.to);
|
|
42
|
+
if (!agent) {
|
|
43
|
+
return {
|
|
44
|
+
requestId: req.id,
|
|
45
|
+
from: req.to,
|
|
46
|
+
status: 'error',
|
|
47
|
+
error: `Agent "${req.to}" not found`,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const message = {
|
|
52
|
+
id: req.id,
|
|
53
|
+
role: 'user',
|
|
54
|
+
content: req.payload,
|
|
55
|
+
timestamp: req.timestamp,
|
|
56
|
+
metadata: { a2a: true, from: req.from, capability: req.capability },
|
|
57
|
+
};
|
|
58
|
+
this.emit('request', req);
|
|
59
|
+
try {
|
|
60
|
+
const timeoutMs = req.timeout ?? 30000;
|
|
61
|
+
const response = await Promise.race([
|
|
62
|
+
agent.handleMessage(message),
|
|
63
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('A2A request timeout')), timeoutMs)),
|
|
64
|
+
]);
|
|
65
|
+
const res = {
|
|
66
|
+
requestId: req.id,
|
|
67
|
+
from: req.to,
|
|
68
|
+
status: 'success',
|
|
69
|
+
payload: response.content,
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
};
|
|
72
|
+
this.emit('response', res);
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const res = {
|
|
77
|
+
requestId: req.id,
|
|
78
|
+
from: req.to,
|
|
79
|
+
status: err.message.includes('timeout') ? 'timeout' : 'error',
|
|
80
|
+
error: err.message,
|
|
81
|
+
timestamp: Date.now(),
|
|
82
|
+
};
|
|
83
|
+
this.emit('response', res);
|
|
84
|
+
return res;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async call(from, to, capability, payload) {
|
|
88
|
+
return this.request({
|
|
89
|
+
id: `a2a_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
90
|
+
from,
|
|
91
|
+
to,
|
|
92
|
+
capability,
|
|
93
|
+
payload,
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.AgentRegistry = AgentRegistry;
|
|
99
|
+
//# sourceMappingURL=a2a.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export interface ApprovalRequest {
|
|
3
|
+
id: string;
|
|
4
|
+
action: string;
|
|
5
|
+
description: string;
|
|
6
|
+
context?: Record<string, unknown>;
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
defaultAction: 'approve' | 'deny';
|
|
9
|
+
createdAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ApprovalResponse {
|
|
12
|
+
requestId: string;
|
|
13
|
+
decision: 'approve' | 'deny';
|
|
14
|
+
respondedBy?: string;
|
|
15
|
+
respondedAt: number;
|
|
16
|
+
timedOut: boolean;
|
|
17
|
+
}
|
|
18
|
+
export type ApprovalHandler = (request: ApprovalRequest) => Promise<ApprovalResponse>;
|
|
19
|
+
export interface HITLConfig {
|
|
20
|
+
/** Actions that always require approval */
|
|
21
|
+
requireApproval: string[];
|
|
22
|
+
/** Default timeout in ms */
|
|
23
|
+
defaultTimeoutMs: number;
|
|
24
|
+
/** Default action on timeout */
|
|
25
|
+
defaultAction: 'approve' | 'deny';
|
|
26
|
+
}
|
|
27
|
+
export declare class HITLManager extends EventEmitter {
|
|
28
|
+
private config;
|
|
29
|
+
private handler;
|
|
30
|
+
private pending;
|
|
31
|
+
private logger;
|
|
32
|
+
constructor(config?: Partial<HITLConfig>);
|
|
33
|
+
setHandler(handler: ApprovalHandler): void;
|
|
34
|
+
needsApproval(action: string): boolean;
|
|
35
|
+
requestApproval(action: string, description: string, context?: Record<string, unknown>): Promise<ApprovalResponse>;
|
|
36
|
+
respond(requestId: string, decision: 'approve' | 'deny', respondedBy?: string): boolean;
|
|
37
|
+
getPending(): ApprovalRequest[];
|
|
38
|
+
private createTimeout;
|
|
39
|
+
private timeoutResponse;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=hitl.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HITLManager = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const logger_1 = require("./logger");
|
|
6
|
+
// ── HITL Manager ────────────────────────────────────────────
|
|
7
|
+
class HITLManager extends events_1.EventEmitter {
|
|
8
|
+
config;
|
|
9
|
+
handler = null;
|
|
10
|
+
pending = new Map();
|
|
11
|
+
logger = new logger_1.Logger('hitl');
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super();
|
|
14
|
+
this.config = {
|
|
15
|
+
requireApproval: config?.requireApproval ?? [],
|
|
16
|
+
defaultTimeoutMs: config?.defaultTimeoutMs ?? 60000,
|
|
17
|
+
defaultAction: config?.defaultAction ?? 'deny',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
setHandler(handler) {
|
|
21
|
+
this.handler = handler;
|
|
22
|
+
}
|
|
23
|
+
needsApproval(action) {
|
|
24
|
+
if (this.config.requireApproval.includes('*'))
|
|
25
|
+
return true;
|
|
26
|
+
return this.config.requireApproval.includes(action);
|
|
27
|
+
}
|
|
28
|
+
async requestApproval(action, description, context) {
|
|
29
|
+
const request = {
|
|
30
|
+
id: `hitl_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
31
|
+
action,
|
|
32
|
+
description,
|
|
33
|
+
context,
|
|
34
|
+
timeoutMs: this.config.defaultTimeoutMs,
|
|
35
|
+
defaultAction: this.config.defaultAction,
|
|
36
|
+
createdAt: Date.now(),
|
|
37
|
+
};
|
|
38
|
+
this.emit('approval:requested', request);
|
|
39
|
+
this.logger.info('Approval requested', { id: request.id, action });
|
|
40
|
+
if (this.handler) {
|
|
41
|
+
try {
|
|
42
|
+
const response = await Promise.race([
|
|
43
|
+
this.handler(request),
|
|
44
|
+
this.createTimeout(request),
|
|
45
|
+
]);
|
|
46
|
+
this.emit('approval:responded', response);
|
|
47
|
+
return response;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return this.timeoutResponse(request);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// No handler: wait for manual response via respond()
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
this.pending.set(request.id, { request, resolve });
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
if (this.pending.has(request.id)) {
|
|
58
|
+
this.pending.delete(request.id);
|
|
59
|
+
const response = this.timeoutResponse(request);
|
|
60
|
+
this.emit('approval:timeout', response);
|
|
61
|
+
resolve(response);
|
|
62
|
+
}
|
|
63
|
+
}, request.timeoutMs);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
respond(requestId, decision, respondedBy) {
|
|
67
|
+
const entry = this.pending.get(requestId);
|
|
68
|
+
if (!entry)
|
|
69
|
+
return false;
|
|
70
|
+
this.pending.delete(requestId);
|
|
71
|
+
const response = {
|
|
72
|
+
requestId,
|
|
73
|
+
decision,
|
|
74
|
+
respondedBy,
|
|
75
|
+
respondedAt: Date.now(),
|
|
76
|
+
timedOut: false,
|
|
77
|
+
};
|
|
78
|
+
entry.resolve(response);
|
|
79
|
+
this.emit('approval:responded', response);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
getPending() {
|
|
83
|
+
return Array.from(this.pending.values()).map(e => e.request);
|
|
84
|
+
}
|
|
85
|
+
createTimeout(request) {
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
setTimeout(() => resolve(this.timeoutResponse(request)), request.timeoutMs);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
timeoutResponse(request) {
|
|
91
|
+
return {
|
|
92
|
+
requestId: request.id,
|
|
93
|
+
decision: request.defaultAction,
|
|
94
|
+
respondedAt: Date.now(),
|
|
95
|
+
timedOut: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.HITLManager = HITLManager;
|
|
100
|
+
//# sourceMappingURL=hitl.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface PooledConnection {
|
|
2
|
+
id: string;
|
|
3
|
+
provider: string;
|
|
4
|
+
createdAt: number;
|
|
5
|
+
lastUsedAt: number;
|
|
6
|
+
inUse: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class ConnectionPool {
|
|
9
|
+
private pool;
|
|
10
|
+
private maxPerProvider;
|
|
11
|
+
private ttlMs;
|
|
12
|
+
private logger;
|
|
13
|
+
constructor(maxPerProvider?: number, ttlMs?: number);
|
|
14
|
+
acquire(provider: string): PooledConnection;
|
|
15
|
+
release(id: string): void;
|
|
16
|
+
getStats(): Record<string, {
|
|
17
|
+
total: number;
|
|
18
|
+
inUse: number;
|
|
19
|
+
}>;
|
|
20
|
+
drain(): void;
|
|
21
|
+
}
|
|
22
|
+
export interface BatchRequest<T> {
|
|
23
|
+
payload: T;
|
|
24
|
+
resolve: (result: unknown) => void;
|
|
25
|
+
reject: (error: Error) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare class RequestBatcher<T> {
|
|
28
|
+
private queue;
|
|
29
|
+
private timer;
|
|
30
|
+
private maxBatchSize;
|
|
31
|
+
private delayMs;
|
|
32
|
+
private processor;
|
|
33
|
+
private logger;
|
|
34
|
+
constructor(processor: (batch: T[]) => Promise<unknown[]>, maxBatchSize?: number, delayMs?: number);
|
|
35
|
+
add(payload: T): Promise<unknown>;
|
|
36
|
+
flush(): Promise<void>;
|
|
37
|
+
get pending(): number;
|
|
38
|
+
}
|
|
39
|
+
export declare class LazyLoader<T> {
|
|
40
|
+
private cache;
|
|
41
|
+
private loaders;
|
|
42
|
+
register(name: string, loader: () => Promise<T>): void;
|
|
43
|
+
get(name: string): Promise<T>;
|
|
44
|
+
isLoaded(name: string): boolean;
|
|
45
|
+
evict(name: string): void;
|
|
46
|
+
clear(): void;
|
|
47
|
+
get loadedCount(): number;
|
|
48
|
+
get registeredCount(): number;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=performance.d.ts.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LazyLoader = exports.RequestBatcher = exports.ConnectionPool = void 0;
|
|
4
|
+
const logger_1 = require("../core/logger");
|
|
5
|
+
class ConnectionPool {
|
|
6
|
+
pool = new Map();
|
|
7
|
+
maxPerProvider;
|
|
8
|
+
ttlMs;
|
|
9
|
+
logger = new logger_1.Logger('connection-pool');
|
|
10
|
+
constructor(maxPerProvider = 5, ttlMs = 300000) {
|
|
11
|
+
this.maxPerProvider = maxPerProvider;
|
|
12
|
+
this.ttlMs = ttlMs;
|
|
13
|
+
}
|
|
14
|
+
acquire(provider) {
|
|
15
|
+
const connections = this.pool.get(provider) ?? [];
|
|
16
|
+
// Cleanup expired
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
const active = connections.filter(c => now - c.createdAt < this.ttlMs);
|
|
19
|
+
// Find available
|
|
20
|
+
const available = active.find(c => !c.inUse);
|
|
21
|
+
if (available) {
|
|
22
|
+
available.inUse = true;
|
|
23
|
+
available.lastUsedAt = now;
|
|
24
|
+
return available;
|
|
25
|
+
}
|
|
26
|
+
// Create new if under limit
|
|
27
|
+
if (active.length < this.maxPerProvider) {
|
|
28
|
+
const conn = {
|
|
29
|
+
id: `conn_${now}_${Math.random().toString(36).slice(2, 8)}`,
|
|
30
|
+
provider,
|
|
31
|
+
createdAt: now,
|
|
32
|
+
lastUsedAt: now,
|
|
33
|
+
inUse: true,
|
|
34
|
+
};
|
|
35
|
+
active.push(conn);
|
|
36
|
+
this.pool.set(provider, active);
|
|
37
|
+
return conn;
|
|
38
|
+
}
|
|
39
|
+
// Wait for one (return oldest used for now)
|
|
40
|
+
const oldest = active.sort((a, b) => a.lastUsedAt - b.lastUsedAt)[0];
|
|
41
|
+
oldest.inUse = true;
|
|
42
|
+
oldest.lastUsedAt = now;
|
|
43
|
+
return oldest;
|
|
44
|
+
}
|
|
45
|
+
release(id) {
|
|
46
|
+
for (const connections of this.pool.values()) {
|
|
47
|
+
const conn = connections.find(c => c.id === id);
|
|
48
|
+
if (conn) {
|
|
49
|
+
conn.inUse = false;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
getStats() {
|
|
55
|
+
const stats = {};
|
|
56
|
+
for (const [provider, connections] of this.pool) {
|
|
57
|
+
stats[provider] = {
|
|
58
|
+
total: connections.length,
|
|
59
|
+
inUse: connections.filter(c => c.inUse).length,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return stats;
|
|
63
|
+
}
|
|
64
|
+
drain() {
|
|
65
|
+
this.pool.clear();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ConnectionPool = ConnectionPool;
|
|
69
|
+
class RequestBatcher {
|
|
70
|
+
queue = [];
|
|
71
|
+
timer = null;
|
|
72
|
+
maxBatchSize;
|
|
73
|
+
delayMs;
|
|
74
|
+
processor;
|
|
75
|
+
logger = new logger_1.Logger('batcher');
|
|
76
|
+
constructor(processor, maxBatchSize = 10, delayMs = 50) {
|
|
77
|
+
this.processor = processor;
|
|
78
|
+
this.maxBatchSize = maxBatchSize;
|
|
79
|
+
this.delayMs = delayMs;
|
|
80
|
+
}
|
|
81
|
+
add(payload) {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
this.queue.push({ payload, resolve, reject });
|
|
84
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
85
|
+
this.flush();
|
|
86
|
+
}
|
|
87
|
+
else if (!this.timer) {
|
|
88
|
+
this.timer = setTimeout(() => this.flush(), this.delayMs);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async flush() {
|
|
93
|
+
if (this.timer) {
|
|
94
|
+
clearTimeout(this.timer);
|
|
95
|
+
this.timer = null;
|
|
96
|
+
}
|
|
97
|
+
if (this.queue.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
100
|
+
try {
|
|
101
|
+
const results = await this.processor(batch.map(b => b.payload));
|
|
102
|
+
batch.forEach((req, i) => req.resolve(results[i]));
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
batch.forEach(req => req.reject(err));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
get pending() {
|
|
109
|
+
return this.queue.length;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.RequestBatcher = RequestBatcher;
|
|
113
|
+
// ── Lazy Loader ─────────────────────────────────────────────
|
|
114
|
+
class LazyLoader {
|
|
115
|
+
cache = new Map();
|
|
116
|
+
loaders = new Map();
|
|
117
|
+
register(name, loader) {
|
|
118
|
+
this.loaders.set(name, loader);
|
|
119
|
+
}
|
|
120
|
+
async get(name) {
|
|
121
|
+
const cached = this.cache.get(name);
|
|
122
|
+
if (cached)
|
|
123
|
+
return cached;
|
|
124
|
+
const loader = this.loaders.get(name);
|
|
125
|
+
if (!loader)
|
|
126
|
+
throw new Error(`No loader registered for "${name}"`);
|
|
127
|
+
const instance = await loader();
|
|
128
|
+
this.cache.set(name, instance);
|
|
129
|
+
return instance;
|
|
130
|
+
}
|
|
131
|
+
isLoaded(name) {
|
|
132
|
+
return this.cache.has(name);
|
|
133
|
+
}
|
|
134
|
+
evict(name) {
|
|
135
|
+
this.cache.delete(name);
|
|
136
|
+
}
|
|
137
|
+
clear() {
|
|
138
|
+
this.cache.clear();
|
|
139
|
+
}
|
|
140
|
+
get loadedCount() {
|
|
141
|
+
return this.cache.size;
|
|
142
|
+
}
|
|
143
|
+
get registeredCount() {
|
|
144
|
+
return this.loaders.size;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.LazyLoader = LazyLoader;
|
|
148
|
+
//# sourceMappingURL=performance.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { Message, IAgent } from './types';
|
|
3
|
+
export interface RoomMessage {
|
|
4
|
+
from: string;
|
|
5
|
+
to?: string;
|
|
6
|
+
topic?: string;
|
|
7
|
+
message: Message;
|
|
8
|
+
}
|
|
9
|
+
export declare class Room extends EventEmitter {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
private agents;
|
|
12
|
+
private subscriptions;
|
|
13
|
+
constructor(name: string);
|
|
14
|
+
addAgent(agent: IAgent): void;
|
|
15
|
+
removeAgent(name: string): void;
|
|
16
|
+
getAgents(): string[];
|
|
17
|
+
subscribe(agentName: string, topic: string): void;
|
|
18
|
+
unsubscribe(agentName: string, topic: string): void;
|
|
19
|
+
getSubscribers(topic: string): string[];
|
|
20
|
+
send(roomMessage: RoomMessage): Promise<Message[]>;
|
|
21
|
+
broadcast(from: string, content: string): Promise<Message[]>;
|
|
22
|
+
publishToTopic(from: string, topic: string, content: string): Promise<Message[]>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=room.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Room = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
class Room extends events_1.EventEmitter {
|
|
6
|
+
name;
|
|
7
|
+
agents = new Map();
|
|
8
|
+
subscriptions = new Map(); // topic -> agentNames
|
|
9
|
+
constructor(name) {
|
|
10
|
+
super();
|
|
11
|
+
this.name = name;
|
|
12
|
+
}
|
|
13
|
+
addAgent(agent) {
|
|
14
|
+
this.agents.set(agent.name, agent);
|
|
15
|
+
this.emit('agent:join', agent.name);
|
|
16
|
+
}
|
|
17
|
+
removeAgent(name) {
|
|
18
|
+
this.agents.delete(name);
|
|
19
|
+
// Remove from all subscriptions
|
|
20
|
+
for (const [, subscribers] of this.subscriptions) {
|
|
21
|
+
subscribers.delete(name);
|
|
22
|
+
}
|
|
23
|
+
this.emit('agent:leave', name);
|
|
24
|
+
}
|
|
25
|
+
getAgents() {
|
|
26
|
+
return Array.from(this.agents.keys());
|
|
27
|
+
}
|
|
28
|
+
subscribe(agentName, topic) {
|
|
29
|
+
if (!this.subscriptions.has(topic)) {
|
|
30
|
+
this.subscriptions.set(topic, new Set());
|
|
31
|
+
}
|
|
32
|
+
this.subscriptions.get(topic).add(agentName);
|
|
33
|
+
}
|
|
34
|
+
unsubscribe(agentName, topic) {
|
|
35
|
+
this.subscriptions.get(topic)?.delete(agentName);
|
|
36
|
+
}
|
|
37
|
+
getSubscribers(topic) {
|
|
38
|
+
return Array.from(this.subscriptions.get(topic) ?? []);
|
|
39
|
+
}
|
|
40
|
+
async send(roomMessage) {
|
|
41
|
+
const responses = [];
|
|
42
|
+
this.emit('message', roomMessage);
|
|
43
|
+
if (roomMessage.to) {
|
|
44
|
+
// Direct message
|
|
45
|
+
const agent = this.agents.get(roomMessage.to);
|
|
46
|
+
if (agent) {
|
|
47
|
+
const response = await agent.handleMessage(roomMessage.message);
|
|
48
|
+
responses.push(response);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (roomMessage.topic) {
|
|
52
|
+
// Topic-based pub/sub
|
|
53
|
+
const subscribers = this.subscriptions.get(roomMessage.topic) ?? new Set();
|
|
54
|
+
for (const name of subscribers) {
|
|
55
|
+
if (name === roomMessage.from)
|
|
56
|
+
continue;
|
|
57
|
+
const agent = this.agents.get(name);
|
|
58
|
+
if (agent) {
|
|
59
|
+
const response = await agent.handleMessage(roomMessage.message);
|
|
60
|
+
responses.push(response);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Broadcast to all except sender
|
|
66
|
+
for (const [name, agent] of this.agents) {
|
|
67
|
+
if (name === roomMessage.from)
|
|
68
|
+
continue;
|
|
69
|
+
const response = await agent.handleMessage(roomMessage.message);
|
|
70
|
+
responses.push(response);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return responses;
|
|
74
|
+
}
|
|
75
|
+
async broadcast(from, content) {
|
|
76
|
+
const message = {
|
|
77
|
+
id: `room_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
78
|
+
role: 'user',
|
|
79
|
+
content,
|
|
80
|
+
timestamp: Date.now(),
|
|
81
|
+
metadata: { room: this.name, from },
|
|
82
|
+
};
|
|
83
|
+
return this.send({ from, message });
|
|
84
|
+
}
|
|
85
|
+
async publishToTopic(from, topic, content) {
|
|
86
|
+
const message = {
|
|
87
|
+
id: `room_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
88
|
+
role: 'user',
|
|
89
|
+
content,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
metadata: { room: this.name, from, topic },
|
|
92
|
+
};
|
|
93
|
+
return this.send({ from, topic, message });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.Room = Room;
|
|
97
|
+
//# sourceMappingURL=room.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TrustLevelType } from '../schema/oad';
|
|
2
|
+
export interface SandboxConfig {
|
|
3
|
+
trustLevel: TrustLevelType;
|
|
4
|
+
agentDir: string;
|
|
5
|
+
networkAllowlist?: string[];
|
|
6
|
+
shellAllowed?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface SandboxRestrictions {
|
|
9
|
+
fileSystem: {
|
|
10
|
+
read: string[];
|
|
11
|
+
write: string[];
|
|
12
|
+
};
|
|
13
|
+
network: {
|
|
14
|
+
allowed: string[];
|
|
15
|
+
};
|
|
16
|
+
shell: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class Sandbox {
|
|
19
|
+
private config;
|
|
20
|
+
private restrictions;
|
|
21
|
+
constructor(config: SandboxConfig);
|
|
22
|
+
get trustLevel(): TrustLevelType;
|
|
23
|
+
getRestrictions(): SandboxRestrictions;
|
|
24
|
+
checkFileAccess(filePath: string, mode: 'read' | 'write'): boolean;
|
|
25
|
+
checkNetworkAccess(url: string): boolean;
|
|
26
|
+
checkShellAccess(): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=sandbox.d.ts.map
|