opc-agent 2.0.0 → 2.0.2
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 +545 -365
- package/dist/channels/email.d.ts +32 -26
- package/dist/channels/email.js +239 -62
- package/dist/channels/feishu.d.ts +21 -6
- package/dist/channels/feishu.js +225 -126
- package/dist/channels/websocket.d.ts +46 -3
- package/dist/channels/websocket.js +306 -37
- package/dist/channels/wechat.d.ts +33 -13
- package/dist/channels/wechat.js +229 -42
- package/dist/cli.js +712 -11
- package/dist/core/a2a.d.ts +17 -0
- package/dist/core/a2a.js +43 -1
- package/dist/core/agent.d.ts +16 -0
- package/dist/core/agent.js +108 -0
- package/dist/core/runtime.d.ts +6 -0
- package/dist/core/runtime.js +161 -2
- package/dist/core/sandbox.d.ts +26 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/workflow-graph.d.ts +93 -0
- package/dist/core/workflow-graph.js +247 -0
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.js +183 -0
- package/dist/eval/index.d.ts +65 -0
- package/dist/eval/index.js +191 -0
- package/dist/index.d.ts +32 -6
- package/dist/index.js +63 -4
- package/dist/plugins/content-filter.d.ts +7 -0
- package/dist/plugins/content-filter.js +25 -0
- package/dist/plugins/index.d.ts +42 -0
- package/dist/plugins/index.js +108 -2
- package/dist/plugins/logger.d.ts +6 -0
- package/dist/plugins/logger.js +20 -0
- package/dist/plugins/rate-limiter.d.ts +7 -0
- package/dist/plugins/rate-limiter.js +35 -0
- package/dist/protocols/a2a/client.d.ts +25 -0
- package/dist/protocols/a2a/client.js +115 -0
- package/dist/protocols/a2a/index.d.ts +6 -0
- package/dist/protocols/a2a/index.js +12 -0
- package/dist/protocols/a2a/server.d.ts +41 -0
- package/dist/protocols/a2a/server.js +295 -0
- package/dist/protocols/a2a/types.d.ts +91 -0
- package/dist/protocols/a2a/types.js +15 -0
- package/dist/protocols/a2a/utils.d.ts +6 -0
- package/dist/protocols/a2a/utils.js +47 -0
- package/dist/protocols/agui/client.d.ts +10 -0
- package/dist/protocols/agui/client.js +75 -0
- package/dist/protocols/agui/index.d.ts +4 -0
- package/dist/protocols/agui/index.js +25 -0
- package/dist/protocols/agui/server.d.ts +37 -0
- package/dist/protocols/agui/server.js +191 -0
- package/dist/protocols/agui/types.d.ts +107 -0
- package/dist/protocols/agui/types.js +17 -0
- package/dist/protocols/index.d.ts +2 -0
- package/dist/protocols/index.js +19 -0
- package/dist/protocols/mcp/agent-tools.d.ts +11 -0
- package/dist/protocols/mcp/agent-tools.js +129 -0
- package/dist/protocols/mcp/index.d.ts +5 -0
- package/dist/protocols/mcp/index.js +11 -0
- package/dist/protocols/mcp/server.d.ts +31 -0
- package/dist/protocols/mcp/server.js +248 -0
- package/dist/protocols/mcp/types.d.ts +92 -0
- package/dist/protocols/mcp/types.js +17 -0
- package/dist/publish/index.d.ts +45 -0
- package/dist/publish/index.js +350 -0
- package/dist/schema/oad.d.ts +682 -65
- package/dist/schema/oad.js +36 -3
- package/dist/security/approval.d.ts +36 -0
- package/dist/security/approval.js +113 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/index.js +8 -0
- package/dist/security/keys.d.ts +16 -0
- package/dist/security/keys.js +117 -0
- package/dist/studio/server.d.ts +63 -0
- package/dist/studio/server.js +625 -0
- package/dist/studio-ui/index.html +662 -0
- package/dist/telemetry/index.d.ts +93 -0
- package/dist/telemetry/index.js +285 -0
- package/package.json +5 -3
- package/scripts/install.ps1 +31 -0
- package/scripts/install.sh +40 -0
- package/src/channels/email.ts +351 -177
- package/src/channels/feishu.ts +349 -236
- package/src/channels/websocket.ts +399 -87
- package/src/channels/wechat.ts +329 -149
- package/src/cli.ts +783 -12
- package/src/core/a2a.ts +60 -0
- package/src/core/agent.ts +125 -0
- package/src/core/runtime.ts +127 -0
- package/src/core/sandbox.ts +143 -0
- package/src/core/workflow-graph.ts +365 -0
- package/src/doctor.ts +156 -0
- package/src/eval/index.ts +211 -0
- package/src/eval/suites/basic.json +16 -0
- package/src/eval/suites/memory.json +12 -0
- package/src/eval/suites/safety.json +14 -0
- package/src/index.ts +58 -6
- package/src/plugins/content-filter.ts +23 -0
- package/src/plugins/index.ts +133 -2
- package/src/plugins/logger.ts +18 -0
- package/src/plugins/rate-limiter.ts +38 -0
- package/src/protocols/a2a/client.ts +132 -0
- package/src/protocols/a2a/index.ts +8 -0
- package/src/protocols/a2a/server.ts +333 -0
- package/src/protocols/a2a/types.ts +88 -0
- package/src/protocols/a2a/utils.ts +50 -0
- package/src/protocols/agui/client.ts +83 -0
- package/src/protocols/agui/index.ts +4 -0
- package/src/protocols/agui/server.ts +218 -0
- package/src/protocols/agui/types.ts +153 -0
- package/src/protocols/index.ts +2 -0
- package/src/protocols/mcp/agent-tools.ts +134 -0
- package/src/protocols/mcp/index.ts +8 -0
- package/src/protocols/mcp/server.ts +262 -0
- package/src/protocols/mcp/types.ts +69 -0
- package/src/publish/index.ts +376 -0
- package/src/schema/oad.ts +39 -2
- package/src/security/approval.ts +131 -0
- package/src/security/index.ts +3 -0
- package/src/security/keys.ts +87 -0
- package/src/studio/server.ts +629 -0
- package/src/studio-ui/index.html +662 -0
- package/src/telemetry/index.ts +324 -0
- package/src/types/agent-workstation.d.ts +2 -0
- package/tests/a2a-protocol.test.ts +285 -0
- package/tests/agui-protocol.test.ts +246 -0
- package/tests/channels/discord.test.ts +79 -0
- package/tests/channels/email.test.ts +148 -0
- package/tests/channels/feishu.test.ts +123 -0
- package/tests/channels/telegram.test.ts +129 -0
- package/tests/channels/websocket.test.ts +53 -0
- package/tests/channels/wechat.test.ts +170 -0
- package/tests/chat-cli.test.ts +160 -0
- package/tests/daemon.test.ts +135 -0
- package/tests/deepbrain-wire.test.ts +234 -0
- package/tests/doctor.test.ts +38 -0
- package/tests/eval.test.ts +173 -0
- package/tests/init-role.test.ts +124 -0
- package/tests/mcp-client.test.ts +92 -0
- package/tests/mcp-server.test.ts +178 -0
- package/tests/plugin-a2a-enhanced.test.ts +230 -0
- package/tests/publish.test.ts +231 -0
- package/tests/scheduler.test.ts +200 -0
- package/tests/security-enhanced.test.ts +233 -0
- package/tests/skill-learner.test.ts +161 -0
- package/tests/studio.test.ts +229 -0
- package/tests/subagent.test.ts +63 -0
- package/tests/telemetry.test.ts +186 -0
- package/tests/tools/builtin-extended.test.ts +138 -0
- package/tests/workflow-graph.test.ts +279 -0
- package/tutorial/customer-service-agent/README.md +612 -0
- package/tutorial/customer-service-agent/SOUL.md +26 -0
- package/tutorial/customer-service-agent/agent.yaml +63 -0
- package/tutorial/customer-service-agent/package.json +19 -0
- package/tutorial/customer-service-agent/src/index.ts +69 -0
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
- package/tutorial/customer-service-agent/tsconfig.json +14 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPC Agent Telemetry — Lightweight OTel-compatible tracing & metrics.
|
|
3
|
+
* Zero external dependencies. Produces OTLP-compatible JSON.
|
|
4
|
+
*/
|
|
5
|
+
export interface Span {
|
|
6
|
+
traceId: string;
|
|
7
|
+
spanId: string;
|
|
8
|
+
parentSpanId?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
kind: 'internal' | 'client' | 'server';
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime?: number;
|
|
13
|
+
status: 'ok' | 'error' | 'unset';
|
|
14
|
+
attributes: Record<string, string | number | boolean>;
|
|
15
|
+
events: SpanEvent[];
|
|
16
|
+
}
|
|
17
|
+
export interface SpanEvent {
|
|
18
|
+
name: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
attributes?: Record<string, string | number | boolean>;
|
|
21
|
+
}
|
|
22
|
+
export interface Metric {
|
|
23
|
+
name: string;
|
|
24
|
+
type: 'counter' | 'gauge' | 'histogram';
|
|
25
|
+
value: number;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
labels: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
export interface TraceExporter {
|
|
30
|
+
export(spans: Span[]): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare function generateTraceId(): string;
|
|
33
|
+
export declare function generateSpanId(): string;
|
|
34
|
+
export declare class Tracer {
|
|
35
|
+
private spans;
|
|
36
|
+
private metrics;
|
|
37
|
+
private maxSpans;
|
|
38
|
+
private maxMetrics;
|
|
39
|
+
private exporters;
|
|
40
|
+
constructor(options?: {
|
|
41
|
+
maxSpans?: number;
|
|
42
|
+
maxMetrics?: number;
|
|
43
|
+
});
|
|
44
|
+
startSpan(name: string, options?: {
|
|
45
|
+
parent?: Span;
|
|
46
|
+
attributes?: Record<string, string | number | boolean>;
|
|
47
|
+
kind?: Span['kind'];
|
|
48
|
+
}): Span;
|
|
49
|
+
endSpan(span: Span, status?: Span['status']): void;
|
|
50
|
+
addEvent(span: Span, name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
51
|
+
increment(name: string, value?: number, labels?: Record<string, string>): void;
|
|
52
|
+
gauge(name: string, value: number, labels?: Record<string, string>): void;
|
|
53
|
+
histogram(name: string, value: number, labels?: Record<string, string>): void;
|
|
54
|
+
private addMetric;
|
|
55
|
+
getSpans(options?: {
|
|
56
|
+
limit?: number;
|
|
57
|
+
traceId?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
since?: number;
|
|
60
|
+
}): Span[];
|
|
61
|
+
getMetrics(options?: {
|
|
62
|
+
name?: string;
|
|
63
|
+
since?: number;
|
|
64
|
+
}): Metric[];
|
|
65
|
+
getTrace(traceId: string): Span[];
|
|
66
|
+
addExporter(exporter: TraceExporter): void;
|
|
67
|
+
exportOTLP(): object;
|
|
68
|
+
getStats(): {
|
|
69
|
+
totalSpans: number;
|
|
70
|
+
totalTraces: number;
|
|
71
|
+
avgDuration: number;
|
|
72
|
+
errorRate: number;
|
|
73
|
+
spansByName: Record<string, number>;
|
|
74
|
+
p50Latency: number;
|
|
75
|
+
p95Latency: number;
|
|
76
|
+
p99Latency: number;
|
|
77
|
+
};
|
|
78
|
+
clear(): void;
|
|
79
|
+
}
|
|
80
|
+
export declare class ConsoleExporter implements TraceExporter {
|
|
81
|
+
export(spans: Span[]): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
export declare class FileExporter implements TraceExporter {
|
|
84
|
+
private filePath;
|
|
85
|
+
constructor(filePath: string);
|
|
86
|
+
export(spans: Span[]): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export declare class OTLPHttpExporter implements TraceExporter {
|
|
89
|
+
private endpoint;
|
|
90
|
+
constructor(endpoint: string);
|
|
91
|
+
export(spans: Span[]): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OPC Agent Telemetry — Lightweight OTel-compatible tracing & metrics.
|
|
4
|
+
* Zero external dependencies. Produces OTLP-compatible JSON.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.OTLPHttpExporter = exports.FileExporter = exports.ConsoleExporter = exports.Tracer = void 0;
|
|
41
|
+
exports.generateTraceId = generateTraceId;
|
|
42
|
+
exports.generateSpanId = generateSpanId;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
// ─── ID Generation ───────────────────────────────────────────
|
|
46
|
+
function generateTraceId() {
|
|
47
|
+
return crypto.randomBytes(16).toString('hex'); // 32 hex chars
|
|
48
|
+
}
|
|
49
|
+
function generateSpanId() {
|
|
50
|
+
return crypto.randomBytes(8).toString('hex'); // 16 hex chars
|
|
51
|
+
}
|
|
52
|
+
// ─── Tracer ──────────────────────────────────────────────────
|
|
53
|
+
class Tracer {
|
|
54
|
+
spans = [];
|
|
55
|
+
metrics = [];
|
|
56
|
+
maxSpans;
|
|
57
|
+
maxMetrics;
|
|
58
|
+
exporters = [];
|
|
59
|
+
constructor(options) {
|
|
60
|
+
this.maxSpans = options?.maxSpans || 10000;
|
|
61
|
+
this.maxMetrics = options?.maxMetrics || 50000;
|
|
62
|
+
}
|
|
63
|
+
startSpan(name, options) {
|
|
64
|
+
const span = {
|
|
65
|
+
traceId: options?.parent?.traceId || generateTraceId(),
|
|
66
|
+
spanId: generateSpanId(),
|
|
67
|
+
parentSpanId: options?.parent?.spanId,
|
|
68
|
+
name,
|
|
69
|
+
kind: options?.kind || 'internal',
|
|
70
|
+
startTime: Date.now(),
|
|
71
|
+
status: 'unset',
|
|
72
|
+
attributes: options?.attributes ? { ...options.attributes } : {},
|
|
73
|
+
events: [],
|
|
74
|
+
};
|
|
75
|
+
this.spans.push(span);
|
|
76
|
+
// Evict oldest spans if over limit
|
|
77
|
+
if (this.spans.length > this.maxSpans) {
|
|
78
|
+
const excess = this.spans.length - this.maxSpans;
|
|
79
|
+
this.spans.splice(0, excess);
|
|
80
|
+
}
|
|
81
|
+
return span;
|
|
82
|
+
}
|
|
83
|
+
endSpan(span, status) {
|
|
84
|
+
span.endTime = Date.now();
|
|
85
|
+
span.status = status || 'ok';
|
|
86
|
+
// Notify exporters
|
|
87
|
+
for (const exporter of this.exporters) {
|
|
88
|
+
exporter.export([span]).catch(() => { });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
addEvent(span, name, attributes) {
|
|
92
|
+
span.events.push({ name, timestamp: Date.now(), attributes });
|
|
93
|
+
}
|
|
94
|
+
// ─── Metrics ─────────────────────────────────────────────
|
|
95
|
+
increment(name, value = 1, labels = {}) {
|
|
96
|
+
this.addMetric(name, 'counter', value, labels);
|
|
97
|
+
}
|
|
98
|
+
gauge(name, value, labels = {}) {
|
|
99
|
+
this.addMetric(name, 'gauge', value, labels);
|
|
100
|
+
}
|
|
101
|
+
histogram(name, value, labels = {}) {
|
|
102
|
+
this.addMetric(name, 'histogram', value, labels);
|
|
103
|
+
}
|
|
104
|
+
addMetric(name, type, value, labels) {
|
|
105
|
+
this.metrics.push({ name, type, value, timestamp: Date.now(), labels });
|
|
106
|
+
if (this.metrics.length > this.maxMetrics) {
|
|
107
|
+
this.metrics.splice(0, this.metrics.length - this.maxMetrics);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ─── Query ───────────────────────────────────────────────
|
|
111
|
+
getSpans(options) {
|
|
112
|
+
let result = [...this.spans];
|
|
113
|
+
if (options?.traceId)
|
|
114
|
+
result = result.filter(s => s.traceId === options.traceId);
|
|
115
|
+
if (options?.name)
|
|
116
|
+
result = result.filter(s => s.name === options.name);
|
|
117
|
+
if (options?.since)
|
|
118
|
+
result = result.filter(s => s.startTime >= options.since);
|
|
119
|
+
// Most recent first
|
|
120
|
+
result.sort((a, b) => b.startTime - a.startTime);
|
|
121
|
+
if (options?.limit)
|
|
122
|
+
result = result.slice(0, options.limit);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
getMetrics(options) {
|
|
126
|
+
let result = [...this.metrics];
|
|
127
|
+
if (options?.name)
|
|
128
|
+
result = result.filter(m => m.name === options.name);
|
|
129
|
+
if (options?.since)
|
|
130
|
+
result = result.filter(m => m.timestamp >= options.since);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
getTrace(traceId) {
|
|
134
|
+
return this.spans.filter(s => s.traceId === traceId).sort((a, b) => a.startTime - b.startTime);
|
|
135
|
+
}
|
|
136
|
+
// ─── Export (OTLP-compatible) ────────────────────────────
|
|
137
|
+
addExporter(exporter) {
|
|
138
|
+
this.exporters.push(exporter);
|
|
139
|
+
}
|
|
140
|
+
exportOTLP() {
|
|
141
|
+
// OTLP JSON format: https://opentelemetry.io/docs/specs/otlp/
|
|
142
|
+
const spansByResource = this.spans.filter(s => s.endTime != null);
|
|
143
|
+
return {
|
|
144
|
+
resourceSpans: [{
|
|
145
|
+
resource: {
|
|
146
|
+
attributes: [
|
|
147
|
+
{ key: 'service.name', value: { stringValue: 'opc-agent' } },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
scopeSpans: [{
|
|
151
|
+
scope: { name: 'opc-telemetry', version: '1.0.0' },
|
|
152
|
+
spans: spansByResource.map(s => ({
|
|
153
|
+
traceId: s.traceId,
|
|
154
|
+
spanId: s.spanId,
|
|
155
|
+
parentSpanId: s.parentSpanId || '',
|
|
156
|
+
name: s.name,
|
|
157
|
+
kind: s.kind === 'server' ? 2 : s.kind === 'client' ? 3 : 1,
|
|
158
|
+
startTimeUnixNano: String(s.startTime * 1_000_000),
|
|
159
|
+
endTimeUnixNano: String((s.endTime || s.startTime) * 1_000_000),
|
|
160
|
+
attributes: Object.entries(s.attributes).map(([key, value]) => ({
|
|
161
|
+
key,
|
|
162
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
163
|
+
: typeof value === 'number' ? (Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value })
|
|
164
|
+
: { boolValue: value },
|
|
165
|
+
})),
|
|
166
|
+
events: s.events.map(e => ({
|
|
167
|
+
timeUnixNano: String(e.timestamp * 1_000_000),
|
|
168
|
+
name: e.name,
|
|
169
|
+
attributes: e.attributes ? Object.entries(e.attributes).map(([key, value]) => ({
|
|
170
|
+
key,
|
|
171
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
172
|
+
: typeof value === 'number' ? { intValue: String(value) }
|
|
173
|
+
: { boolValue: value },
|
|
174
|
+
})) : [],
|
|
175
|
+
})),
|
|
176
|
+
status: {
|
|
177
|
+
code: s.status === 'ok' ? 1 : s.status === 'error' ? 2 : 0,
|
|
178
|
+
},
|
|
179
|
+
})),
|
|
180
|
+
}],
|
|
181
|
+
}],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// ─── Stats ───────────────────────────────────────────────
|
|
185
|
+
getStats() {
|
|
186
|
+
const completed = this.spans.filter(s => s.endTime != null);
|
|
187
|
+
const durations = completed.map(s => s.endTime - s.startTime).sort((a, b) => a - b);
|
|
188
|
+
const traceIds = new Set(this.spans.map(s => s.traceId));
|
|
189
|
+
const errors = completed.filter(s => s.status === 'error').length;
|
|
190
|
+
const spansByName = {};
|
|
191
|
+
for (const s of this.spans) {
|
|
192
|
+
spansByName[s.name] = (spansByName[s.name] || 0) + 1;
|
|
193
|
+
}
|
|
194
|
+
const percentile = (arr, p) => {
|
|
195
|
+
if (arr.length === 0)
|
|
196
|
+
return 0;
|
|
197
|
+
const idx = Math.ceil(arr.length * p / 100) - 1;
|
|
198
|
+
return arr[Math.max(0, idx)];
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
totalSpans: this.spans.length,
|
|
202
|
+
totalTraces: traceIds.size,
|
|
203
|
+
avgDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
|
|
204
|
+
errorRate: completed.length > 0 ? errors / completed.length : 0,
|
|
205
|
+
spansByName,
|
|
206
|
+
p50Latency: percentile(durations, 50),
|
|
207
|
+
p95Latency: percentile(durations, 95),
|
|
208
|
+
p99Latency: percentile(durations, 99),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
clear() {
|
|
212
|
+
this.spans = [];
|
|
213
|
+
this.metrics = [];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.Tracer = Tracer;
|
|
217
|
+
// ─── Exporters ───────────────────────────────────────────────
|
|
218
|
+
class ConsoleExporter {
|
|
219
|
+
async export(spans) {
|
|
220
|
+
for (const span of spans) {
|
|
221
|
+
const duration = span.endTime ? `${span.endTime - span.startTime}ms` : 'ongoing';
|
|
222
|
+
console.log(`[TRACE] ${span.name} (${duration}) [${span.status}] trace=${span.traceId.slice(0, 8)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.ConsoleExporter = ConsoleExporter;
|
|
227
|
+
class FileExporter {
|
|
228
|
+
filePath;
|
|
229
|
+
constructor(filePath) {
|
|
230
|
+
this.filePath = filePath;
|
|
231
|
+
}
|
|
232
|
+
async export(spans) {
|
|
233
|
+
const lines = spans.map(s => JSON.stringify(s)).join('\n') + '\n';
|
|
234
|
+
fs.appendFileSync(this.filePath, lines);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
exports.FileExporter = FileExporter;
|
|
238
|
+
class OTLPHttpExporter {
|
|
239
|
+
endpoint;
|
|
240
|
+
constructor(endpoint) {
|
|
241
|
+
this.endpoint = endpoint.replace(/\/$/, '');
|
|
242
|
+
}
|
|
243
|
+
async export(spans) {
|
|
244
|
+
const body = {
|
|
245
|
+
resourceSpans: [{
|
|
246
|
+
resource: {
|
|
247
|
+
attributes: [
|
|
248
|
+
{ key: 'service.name', value: { stringValue: 'opc-agent' } },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
scopeSpans: [{
|
|
252
|
+
scope: { name: 'opc-telemetry', version: '1.0.0' },
|
|
253
|
+
spans: spans.filter(s => s.endTime).map(s => ({
|
|
254
|
+
traceId: s.traceId,
|
|
255
|
+
spanId: s.spanId,
|
|
256
|
+
parentSpanId: s.parentSpanId || '',
|
|
257
|
+
name: s.name,
|
|
258
|
+
kind: s.kind === 'server' ? 2 : s.kind === 'client' ? 3 : 1,
|
|
259
|
+
startTimeUnixNano: String(s.startTime * 1_000_000),
|
|
260
|
+
endTimeUnixNano: String((s.endTime || s.startTime) * 1_000_000),
|
|
261
|
+
attributes: Object.entries(s.attributes).map(([key, value]) => ({
|
|
262
|
+
key,
|
|
263
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
264
|
+
: typeof value === 'number' ? { intValue: String(value) }
|
|
265
|
+
: { boolValue: value },
|
|
266
|
+
})),
|
|
267
|
+
status: { code: s.status === 'ok' ? 1 : s.status === 'error' ? 2 : 0 },
|
|
268
|
+
})),
|
|
269
|
+
}],
|
|
270
|
+
}],
|
|
271
|
+
};
|
|
272
|
+
try {
|
|
273
|
+
await fetch(`${this.endpoint}/v1/traces`, {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
headers: { 'Content-Type': 'application/json' },
|
|
276
|
+
body: JSON.stringify(body),
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Best effort
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
exports.OTLPHttpExporter = OTLPHttpExporter;
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opc-agent",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Open Agent Framework — Build, test, and run AI Agents for business workstations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
|
+
"postbuild": "xcopy /E /I /Y src\\studio-ui dist\\studio-ui",
|
|
12
13
|
"test": "vitest run",
|
|
13
14
|
"dev": "tsc --watch",
|
|
14
15
|
"lint": "tsc --noEmit",
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
"url": "https://github.com/Deepleaper/opc-agent.git"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
35
|
+
"agent-workstation": "^1.2.1",
|
|
34
36
|
"agentkits": "^0.1.0",
|
|
35
37
|
"commander": "^12.0.0",
|
|
36
38
|
"express": "^4.21.0",
|
|
@@ -44,7 +46,7 @@
|
|
|
44
46
|
"@types/node": "^20.11.0",
|
|
45
47
|
"@types/ws": "^8.18.1",
|
|
46
48
|
"typescript": "^5.5.0",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
+
"vitepress": "^1.5.0",
|
|
50
|
+
"vitest": "^2.0.0"
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# OPC Agent — Windows installer
|
|
2
|
+
# Usage: irm https://raw.githubusercontent.com/Deepleaper/opc-agent/main/scripts/install.ps1 | iex
|
|
3
|
+
|
|
4
|
+
Write-Host "🤖 Installing OPC Agent..." -ForegroundColor Cyan
|
|
5
|
+
|
|
6
|
+
# Check Node.js
|
|
7
|
+
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
|
8
|
+
Write-Host "❌ Node.js is required. Install from https://nodejs.org (v18+)" -ForegroundColor Red
|
|
9
|
+
exit 1
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
$nodeVer = (node -v) -replace 'v','' -split '\.' | Select-Object -First 1
|
|
13
|
+
if ([int]$nodeVer -lt 18) {
|
|
14
|
+
Write-Host "❌ Node.js 18+ required (found $(node -v))" -ForegroundColor Red
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Write-Host "📦 Installing opc-agent globally..."
|
|
19
|
+
npm install -g opc-agent
|
|
20
|
+
|
|
21
|
+
Write-Host "`n✅ OPC Agent installed!" -ForegroundColor Green
|
|
22
|
+
Write-Host @"
|
|
23
|
+
|
|
24
|
+
Quick start:
|
|
25
|
+
opc init my-agent
|
|
26
|
+
cd my-agent
|
|
27
|
+
npm install
|
|
28
|
+
opc chat
|
|
29
|
+
|
|
30
|
+
Run 'opc doctor' to check your environment.
|
|
31
|
+
"@
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# OPC Agent — One-line installer
|
|
3
|
+
# Usage: curl -fsSL https://raw.githubusercontent.com/Deepleaper/opc-agent/main/scripts/install.sh | bash
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "🤖 Installing OPC Agent..."
|
|
8
|
+
|
|
9
|
+
# Check Node.js
|
|
10
|
+
if ! command -v node &> /dev/null; then
|
|
11
|
+
echo "❌ Node.js is required. Install from https://nodejs.org (v18+)"
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
NODE_VERSION=$(node -v | sed 's/v//' | cut -d. -f1)
|
|
16
|
+
if [ "$NODE_VERSION" -lt 18 ]; then
|
|
17
|
+
echo "❌ Node.js 18+ required (found v$(node -v))"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Install globally
|
|
22
|
+
echo "📦 Installing opc-agent globally..."
|
|
23
|
+
npm install -g opc-agent
|
|
24
|
+
|
|
25
|
+
# Verify
|
|
26
|
+
if command -v opc &> /dev/null; then
|
|
27
|
+
echo ""
|
|
28
|
+
echo "✅ OPC Agent installed successfully!"
|
|
29
|
+
echo ""
|
|
30
|
+
echo "Quick start:"
|
|
31
|
+
echo " opc init my-agent"
|
|
32
|
+
echo " cd my-agent"
|
|
33
|
+
echo " npm install"
|
|
34
|
+
echo " opc chat"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Run 'opc doctor' to check your environment."
|
|
37
|
+
else
|
|
38
|
+
echo "⚠️ Installed but 'opc' command not found in PATH."
|
|
39
|
+
echo "Try: npx opc-agent --help"
|
|
40
|
+
fi
|