opc-agent 1.3.1 → 1.3.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/CHANGELOG.md +6 -0
- package/CONTRIBUTING.md +75 -75
- package/README.md +358 -235
- package/README.zh-CN.md +415 -415
- package/dist/cli.js +34 -118
- package/dist/core/dashboard.d.ts +35 -0
- package/dist/core/dashboard.js +157 -0
- package/dist/core/priority.d.ts +52 -0
- package/dist/core/priority.js +102 -0
- package/dist/deploy/hermes.js +22 -22
- package/dist/deploy/openclaw.js +40 -31
- package/dist/index.d.ts +10 -3
- package/dist/index.js +15 -6
- package/dist/schema/oad.d.ts +2 -1
- package/dist/templates/code-reviewer.d.ts +8 -0
- package/dist/templates/code-reviewer.js +9 -5
- package/dist/templates/customer-service.d.ts +8 -0
- package/dist/templates/customer-service.js +6 -2
- package/dist/templates/data-analyst.d.ts +8 -0
- package/dist/templates/data-analyst.js +9 -5
- package/dist/templates/knowledge-base.d.ts +8 -0
- package/dist/templates/knowledge-base.js +6 -2
- package/dist/templates/sales-assistant.d.ts +8 -0
- package/dist/templates/sales-assistant.js +8 -4
- package/dist/templates/teacher.d.ts +8 -0
- package/dist/templates/teacher.js +10 -6
- package/docs/.vitepress/config.ts +103 -103
- package/docs/api/cli.md +48 -48
- package/docs/api/oad-schema.md +64 -64
- package/docs/api/sdk.md +80 -80
- package/docs/guide/concepts.md +51 -51
- package/docs/guide/configuration.md +79 -79
- package/docs/guide/deployment.md +42 -42
- package/docs/guide/getting-started.md +44 -44
- package/docs/guide/templates.md +28 -28
- package/docs/guide/testing.md +84 -84
- package/docs/index.md +27 -27
- package/docs/zh/api/cli.md +54 -54
- package/docs/zh/api/oad-schema.md +87 -87
- package/docs/zh/api/sdk.md +102 -102
- package/docs/zh/guide/concepts.md +104 -104
- package/docs/zh/guide/configuration.md +135 -135
- package/docs/zh/guide/deployment.md +81 -81
- package/docs/zh/guide/getting-started.md +82 -82
- package/docs/zh/guide/templates.md +84 -84
- package/docs/zh/guide/testing.md +88 -88
- package/docs/zh/index.md +27 -27
- package/examples/customer-service-demo/README.md +90 -90
- package/examples/customer-service-demo/oad.yaml +107 -107
- package/package.json +1 -1
- package/src/analytics/index.ts +66 -66
- package/src/channels/discord.ts +192 -192
- package/src/channels/email.ts +177 -177
- package/src/channels/feishu.ts +236 -236
- package/src/channels/index.ts +15 -15
- package/src/channels/slack.ts +160 -160
- package/src/channels/telegram.ts +90 -90
- package/src/channels/voice.ts +106 -106
- package/src/channels/webhook.ts +199 -199
- package/src/channels/websocket.ts +87 -87
- package/src/channels/wechat.ts +149 -149
- package/src/cli.ts +32 -124
- package/src/core/a2a.ts +143 -143
- package/src/core/agent.ts +152 -152
- package/src/core/analytics-engine.ts +186 -186
- package/src/core/auth.ts +57 -57
- package/src/core/cache.ts +141 -141
- package/src/core/compose.ts +77 -77
- package/src/core/config.ts +14 -14
- package/src/core/dashboard.ts +219 -0
- package/src/core/errors.ts +148 -148
- package/src/core/hitl.ts +138 -138
- package/src/core/logger.ts +57 -57
- package/src/core/orchestrator.ts +215 -215
- package/src/core/performance.ts +187 -187
- package/src/core/priority.ts +140 -0
- package/src/core/rate-limiter.ts +128 -128
- package/src/core/room.ts +109 -109
- package/src/core/runtime.ts +152 -152
- package/src/core/sandbox.ts +101 -101
- package/src/core/security.ts +171 -171
- package/src/core/types.ts +68 -68
- package/src/core/versioning.ts +106 -106
- package/src/core/watch.ts +178 -178
- package/src/core/workflow.ts +235 -235
- package/src/deploy/hermes.ts +156 -156
- package/src/deploy/openclaw.ts +200 -190
- package/src/dtv/data.ts +29 -0
- package/src/dtv/trust.ts +43 -0
- package/src/dtv/value.ts +47 -0
- package/src/i18n/index.ts +216 -216
- package/src/index.ts +10 -3
- package/src/marketplace/index.ts +223 -0
- package/src/memory/deepbrain.ts +108 -108
- package/src/memory/index.ts +34 -34
- package/src/plugins/index.ts +208 -208
- package/src/schema/oad.ts +155 -154
- package/src/skills/base.ts +16 -16
- package/src/skills/document.ts +100 -100
- package/src/skills/http.ts +35 -35
- package/src/skills/index.ts +27 -27
- package/src/skills/scheduler.ts +80 -80
- package/src/skills/webhook-trigger.ts +59 -59
- package/src/templates/code-reviewer.ts +34 -30
- package/src/templates/customer-service.ts +80 -76
- package/src/templates/data-analyst.ts +70 -66
- package/src/templates/executive-assistant.ts +71 -71
- package/src/templates/financial-advisor.ts +60 -60
- package/src/templates/knowledge-base.ts +31 -27
- package/src/templates/legal-assistant.ts +71 -71
- package/src/templates/sales-assistant.ts +79 -75
- package/src/templates/teacher.ts +79 -75
- package/src/testing/index.ts +181 -181
- package/src/tools/calculator.ts +73 -73
- package/src/tools/datetime.ts +149 -149
- package/src/tools/json-transform.ts +187 -187
- package/src/tools/mcp.ts +76 -76
- package/src/tools/text-analysis.ts +116 -116
- package/templates/Dockerfile +15 -15
- package/templates/code-reviewer/README.md +27 -27
- package/templates/code-reviewer/oad.yaml +41 -41
- package/templates/customer-service/README.md +22 -22
- package/templates/customer-service/oad.yaml +36 -36
- package/templates/docker-compose.yml +21 -21
- package/templates/ecommerce-assistant/README.md +45 -45
- package/templates/ecommerce-assistant/oad.yaml +47 -47
- package/templates/knowledge-base/README.md +28 -28
- package/templates/knowledge-base/oad.yaml +38 -38
- package/templates/sales-assistant/README.md +26 -26
- package/templates/sales-assistant/oad.yaml +43 -43
- package/templates/tech-support/README.md +43 -43
- package/templates/tech-support/oad.yaml +45 -45
- package/tests/a2a.test.ts +66 -66
- package/tests/agent.test.ts +72 -72
- package/tests/analytics.test.ts +50 -50
- package/tests/channel.test.ts +39 -39
- package/tests/e2e.test.ts +134 -134
- package/tests/errors.test.ts +83 -83
- package/tests/hitl.test.ts +71 -71
- package/tests/i18n.test.ts +41 -41
- package/tests/mcp.test.ts +54 -54
- package/tests/oad.test.ts +68 -68
- package/tests/performance.test.ts +115 -115
- package/tests/plugin.test.ts +74 -74
- package/tests/room.test.ts +106 -106
- package/tests/runtime.test.ts +42 -42
- package/tests/sandbox.test.ts +46 -46
- package/tests/security.test.ts +60 -60
- package/tests/templates.test.ts +77 -77
- package/tests/v070.test.ts +76 -76
- package/tests/versioning.test.ts +75 -75
- package/tests/voice.test.ts +61 -61
- package/tests/webhook.test.ts +29 -29
- package/tests/workflow.test.ts +143 -143
- package/tsconfig.json +19 -19
- package/vitest.config.ts +9 -9
- package/.github/workflows/ci.yml +0 -24
- package/dist/traces/index.d.ts +0 -49
- package/dist/traces/index.js +0 -102
- package/src/traces/index.ts +0 -132
package/dist/cli.js
CHANGED
|
@@ -61,6 +61,7 @@ const workflow_1 = require("./core/workflow");
|
|
|
61
61
|
const versioning_1 = require("./core/versioning");
|
|
62
62
|
const providers_1 = require("./providers");
|
|
63
63
|
const knowledge_1 = require("./core/knowledge");
|
|
64
|
+
const marketplace_1 = require("./marketplace");
|
|
64
65
|
const program = new commander_1.Command();
|
|
65
66
|
const color = {
|
|
66
67
|
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
@@ -683,23 +684,51 @@ kbCmd.command('clear').action(() => {
|
|
|
683
684
|
kb.clear();
|
|
684
685
|
console.log(`${icon.success} Knowledge base cleared.`);
|
|
685
686
|
});
|
|
686
|
-
// 📦
|
|
687
|
+
// 📦 Marketplace commands ───────────────────────────────────
|
|
687
688
|
program
|
|
688
689
|
.command('publish')
|
|
689
690
|
.description('Package agent for distribution')
|
|
690
691
|
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
691
692
|
.option('-o, --output <dir>', 'Output directory', '.')
|
|
692
693
|
.option('--include-kb', 'Include knowledge base')
|
|
693
|
-
.action(async () => {
|
|
694
|
-
|
|
694
|
+
.action(async (opts) => {
|
|
695
|
+
try {
|
|
696
|
+
console.log(`\n${icon.package} Packaging agent...\n`);
|
|
697
|
+
const result = await (0, marketplace_1.publishAgent)({
|
|
698
|
+
oadPath: opts.file,
|
|
699
|
+
outputDir: opts.output,
|
|
700
|
+
includeKnowledge: opts.includeKb,
|
|
701
|
+
});
|
|
702
|
+
console.log(`${icon.success} Published: ${color.bold(result.archivePath)}`);
|
|
703
|
+
console.log(` Name: ${result.manifest.name}`);
|
|
704
|
+
console.log(` Version: ${result.manifest.version}`);
|
|
705
|
+
console.log(` Files: ${result.manifest.files.length}`);
|
|
706
|
+
console.log();
|
|
707
|
+
}
|
|
708
|
+
catch (err) {
|
|
709
|
+
console.error(`${icon.error} Publish failed:`, err instanceof Error ? err.message : err);
|
|
710
|
+
process.exit(1);
|
|
711
|
+
}
|
|
695
712
|
});
|
|
696
713
|
program
|
|
697
714
|
.command('install')
|
|
698
715
|
.description('Install agent from package')
|
|
699
716
|
.argument('<source>', 'Package file path or URL')
|
|
700
717
|
.option('-d, --dir <dir>', 'Install directory')
|
|
701
|
-
.action(async () => {
|
|
702
|
-
|
|
718
|
+
.action(async (source, opts) => {
|
|
719
|
+
try {
|
|
720
|
+
console.log(`\n${icon.package} Installing agent from ${color.bold(source)}...\n`);
|
|
721
|
+
const result = await (0, marketplace_1.installAgent)({ source, targetDir: opts.dir });
|
|
722
|
+
console.log(`${icon.success} Installed: ${color.bold(result.manifest.name)} v${result.manifest.version}`);
|
|
723
|
+
console.log(` Directory: ${result.dir}`);
|
|
724
|
+
console.log(`\n${color.bold('Next steps:')}`);
|
|
725
|
+
console.log(` cd ${result.dir}`);
|
|
726
|
+
console.log(` opc run\n`);
|
|
727
|
+
}
|
|
728
|
+
catch (err) {
|
|
729
|
+
console.error(`${icon.error} Install failed:`, err instanceof Error ? err.message : err);
|
|
730
|
+
process.exit(1);
|
|
731
|
+
}
|
|
703
732
|
});
|
|
704
733
|
// 🔌 Plugin commands ────────────────────────────────────────
|
|
705
734
|
const pluginCmd = program.command('plugin').description('Manage plugins');
|
|
@@ -809,118 +838,5 @@ program
|
|
|
809
838
|
process.exit(1);
|
|
810
839
|
}
|
|
811
840
|
});
|
|
812
|
-
// ── Brain command ────────────────────────────────────────────
|
|
813
|
-
program
|
|
814
|
-
.command('brain')
|
|
815
|
-
.description('Show agent memory/brain status from DeepBrain')
|
|
816
|
-
.option('--url <url>', 'DeepBrain server URL', 'http://localhost:3333')
|
|
817
|
-
.action(async (opts) => {
|
|
818
|
-
console.log(`\n${icon.gear} ${color.bold('DeepBrain Status')} — ${color.dim(opts.url)}\n`);
|
|
819
|
-
try {
|
|
820
|
-
const res = await fetch(`${opts.url}/api/stats`);
|
|
821
|
-
if (!res.ok)
|
|
822
|
-
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
823
|
-
const stats = (await res.json());
|
|
824
|
-
const rows = [
|
|
825
|
-
['Total Pages', String(stats.totalPages ?? stats.pages ?? '-')],
|
|
826
|
-
['Total Chunks', String(stats.totalChunks ?? stats.chunks ?? '-')],
|
|
827
|
-
['Memory Tiers', String(stats.memoryTiers ?? stats.tiers ?? '-')],
|
|
828
|
-
['Index Size', stats.indexSize ?? '-'],
|
|
829
|
-
['Last Updated', stats.lastUpdated ?? stats.updatedAt ?? '-'],
|
|
830
|
-
];
|
|
831
|
-
const maxKey = Math.max(...rows.map(([k]) => k.length));
|
|
832
|
-
for (const [key, val] of rows) {
|
|
833
|
-
console.log(` ${color.cyan(key.padEnd(maxKey))} ${val}`);
|
|
834
|
-
}
|
|
835
|
-
console.log();
|
|
836
|
-
}
|
|
837
|
-
catch (err) {
|
|
838
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
839
|
-
if (msg.includes('ECONNREFUSED') || msg.includes('fetch failed')) {
|
|
840
|
-
console.log(` ${icon.warn} Cannot connect to DeepBrain at ${opts.url}`);
|
|
841
|
-
console.log(` ${color.dim('Is the server running? Start with: deepbrain serve')}\n`);
|
|
842
|
-
}
|
|
843
|
-
else {
|
|
844
|
-
console.error(` ${icon.error} ${msg}\n`);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
});
|
|
848
|
-
// ── Logs command ─────────────────────────────────────────────
|
|
849
|
-
program
|
|
850
|
-
.command('logs')
|
|
851
|
-
.description('Show recent agent traces')
|
|
852
|
-
.option('-n, --limit <n>', 'Number of spans to show', '20')
|
|
853
|
-
.option('-f, --follow', 'Keep watching for new spans')
|
|
854
|
-
.action(async (opts) => {
|
|
855
|
-
const { TraceCollector } = await Promise.resolve().then(() => __importStar(require('./traces')));
|
|
856
|
-
const collector = new TraceCollector();
|
|
857
|
-
const limit = parseInt(opts.limit) || 20;
|
|
858
|
-
const printSpans = (spans) => {
|
|
859
|
-
const slice = spans.slice(-limit);
|
|
860
|
-
if (slice.length === 0) {
|
|
861
|
-
console.log(` ${icon.info} No traces yet. Interact with the agent to generate traces.`);
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
for (const span of slice) {
|
|
865
|
-
const duration = span.endTime
|
|
866
|
-
? `${span.endTime.getTime() - span.startTime.getTime()}ms`
|
|
867
|
-
: 'ongoing';
|
|
868
|
-
const statusIcon = span.status === 'ok' ? icon.success : span.status === 'error' ? icon.error : color.dim('○');
|
|
869
|
-
const time = span.startTime.toLocaleTimeString();
|
|
870
|
-
console.log(` ${statusIcon} ${color.dim(time)} ${color.bold(span.name)} ${color.dim(duration)}`);
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
console.log(`\n${icon.gear} ${color.bold('Agent Traces')}\n`);
|
|
874
|
-
const spans = collector.getBufferedSpans();
|
|
875
|
-
printSpans(spans);
|
|
876
|
-
if (opts.follow) {
|
|
877
|
-
console.log(`\n ${color.dim('Watching for new traces... (Ctrl+C to stop)')}\n`);
|
|
878
|
-
let lastCount = spans.length;
|
|
879
|
-
const interval = setInterval(() => {
|
|
880
|
-
const current = collector.getBufferedSpans();
|
|
881
|
-
if (current.length > lastCount) {
|
|
882
|
-
const newSpans = current.slice(lastCount);
|
|
883
|
-
printSpans(newSpans);
|
|
884
|
-
lastCount = current.length;
|
|
885
|
-
}
|
|
886
|
-
}, 1000);
|
|
887
|
-
process.on('SIGINT', () => { clearInterval(interval); process.exit(0); });
|
|
888
|
-
}
|
|
889
|
-
else {
|
|
890
|
-
console.log();
|
|
891
|
-
}
|
|
892
|
-
});
|
|
893
|
-
// ── Score command ────────────────────────────────────────────
|
|
894
|
-
program
|
|
895
|
-
.command('score')
|
|
896
|
-
.description('Show agent performance score')
|
|
897
|
-
.action(async () => {
|
|
898
|
-
console.log(`\n${icon.gear} ${color.bold('Agent Performance Score')}\n`);
|
|
899
|
-
try {
|
|
900
|
-
const engine = new analytics_engine_1.AnalyticsEngine('.');
|
|
901
|
-
const stats = engine.getStats();
|
|
902
|
-
if (!stats || stats.totalMessages === 0) {
|
|
903
|
-
console.log(` ${icon.info} No score data yet. Run the agent first.\n`);
|
|
904
|
-
return;
|
|
905
|
-
}
|
|
906
|
-
const errorRate = stats.totalMessages > 0 ? (stats.totalErrors / stats.totalMessages) : 0;
|
|
907
|
-
const rows = [
|
|
908
|
-
['Total Messages', String(stats.totalMessages)],
|
|
909
|
-
['Total LLM Calls', String(stats.totalLLMCalls)],
|
|
910
|
-
['Total Tool Uses', String(stats.totalToolUses)],
|
|
911
|
-
['Avg Response Time', `${stats.avgResponseTimeMs}ms`],
|
|
912
|
-
['Error Rate', `${(errorRate * 100).toFixed(1)}%`],
|
|
913
|
-
['Token Usage', `${stats.totalTokens.total} tokens (in: ${stats.totalTokens.input}, out: ${stats.totalTokens.output})`],
|
|
914
|
-
];
|
|
915
|
-
const maxKey = Math.max(...rows.map(([k]) => k.length));
|
|
916
|
-
for (const [key, val] of rows) {
|
|
917
|
-
console.log(` ${color.cyan(key.padEnd(maxKey))} ${val}`);
|
|
918
|
-
}
|
|
919
|
-
console.log();
|
|
920
|
-
}
|
|
921
|
-
catch {
|
|
922
|
-
console.log(` ${icon.info} No score data yet. Run the agent first.\n`);
|
|
923
|
-
}
|
|
924
|
-
});
|
|
925
841
|
program.parse();
|
|
926
842
|
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface DashboardConfig {
|
|
2
|
+
/** Enable the dashboard (default: false) */
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
/** HTTP port (default: 4100) */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** Bind address (default: 127.0.0.1 for security) */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** Enable CORS (default: false) */
|
|
9
|
+
cors?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface SessionSummary {
|
|
12
|
+
id: string;
|
|
13
|
+
channel: string;
|
|
14
|
+
messages: number;
|
|
15
|
+
lastActive: number;
|
|
16
|
+
status: 'active' | 'idle' | 'closed';
|
|
17
|
+
}
|
|
18
|
+
export declare class Dashboard {
|
|
19
|
+
private app;
|
|
20
|
+
private server;
|
|
21
|
+
private config;
|
|
22
|
+
private startTime;
|
|
23
|
+
private stats;
|
|
24
|
+
constructor(config: DashboardConfig);
|
|
25
|
+
private setupRoutes;
|
|
26
|
+
private getState;
|
|
27
|
+
trackSession(session: SessionSummary): void;
|
|
28
|
+
trackToolCall(toolName: string): void;
|
|
29
|
+
trackChannel(name: string, connected: boolean, messages?: number): void;
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
private renderHTML;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=dashboard.d.ts.map
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Dashboard = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
// ─── Dashboard Server ────────────────────────────────────────
|
|
9
|
+
class Dashboard {
|
|
10
|
+
app = (0, express_1.default)();
|
|
11
|
+
server = null;
|
|
12
|
+
config;
|
|
13
|
+
startTime = Date.now();
|
|
14
|
+
stats = {
|
|
15
|
+
sessions: new Map(),
|
|
16
|
+
toolInvocations: new Map(),
|
|
17
|
+
channelStats: new Map(),
|
|
18
|
+
};
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = {
|
|
21
|
+
enabled: config.enabled,
|
|
22
|
+
port: config.port ?? 4100,
|
|
23
|
+
host: config.host ?? '127.0.0.1',
|
|
24
|
+
cors: config.cors ?? false,
|
|
25
|
+
};
|
|
26
|
+
this.setupRoutes();
|
|
27
|
+
}
|
|
28
|
+
setupRoutes() {
|
|
29
|
+
if (this.config.cors) {
|
|
30
|
+
this.app.use((_req, res, next) => {
|
|
31
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
32
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
33
|
+
next();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
this.app.use(express_1.default.json());
|
|
37
|
+
// Health check
|
|
38
|
+
this.app.get('/api/health', (_req, res) => {
|
|
39
|
+
res.json({ status: 'ok', uptime: Date.now() - this.startTime });
|
|
40
|
+
});
|
|
41
|
+
// Overview state
|
|
42
|
+
this.app.get('/api/state', (_req, res) => {
|
|
43
|
+
res.json(this.getState());
|
|
44
|
+
});
|
|
45
|
+
// Sessions
|
|
46
|
+
this.app.get('/api/sessions', (_req, res) => {
|
|
47
|
+
res.json([...this.stats.sessions.values()]);
|
|
48
|
+
});
|
|
49
|
+
// Tools
|
|
50
|
+
this.app.get('/api/tools', (_req, res) => {
|
|
51
|
+
const tools = [];
|
|
52
|
+
for (const [name, stat] of this.stats.toolInvocations) {
|
|
53
|
+
tools.push({ name, type: 'builtin', enabled: true, invocations: stat.count, lastUsed: stat.lastUsed });
|
|
54
|
+
}
|
|
55
|
+
res.json(tools);
|
|
56
|
+
});
|
|
57
|
+
// Channels
|
|
58
|
+
this.app.get('/api/channels', (_req, res) => {
|
|
59
|
+
const channels = [];
|
|
60
|
+
for (const [name, stat] of this.stats.channelStats) {
|
|
61
|
+
channels.push({ name, type: name, connected: stat.connected, messageCount: stat.messages });
|
|
62
|
+
}
|
|
63
|
+
res.json(channels);
|
|
64
|
+
});
|
|
65
|
+
// Simple HTML dashboard
|
|
66
|
+
this.app.get('/', (_req, res) => {
|
|
67
|
+
res.send(this.renderHTML());
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
getState() {
|
|
71
|
+
return {
|
|
72
|
+
agent: { name: 'opc-agent', version: '1.3.0', status: 'running', uptime: Date.now() - this.startTime },
|
|
73
|
+
sessions: [...this.stats.sessions.values()],
|
|
74
|
+
tools: [...this.stats.toolInvocations.entries()].map(([name, s]) => ({
|
|
75
|
+
name, type: 'builtin', enabled: true, invocations: s.count, lastUsed: s.lastUsed,
|
|
76
|
+
})),
|
|
77
|
+
channels: [...this.stats.channelStats.entries()].map(([name, s]) => ({
|
|
78
|
+
name, type: name, connected: s.connected, messageCount: s.messages,
|
|
79
|
+
})),
|
|
80
|
+
memory: { provider: 'unknown', entries: 0 },
|
|
81
|
+
modelAuth: { providers: [] },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// ─── Event Tracking ──────────────────────────────────────
|
|
85
|
+
trackSession(session) {
|
|
86
|
+
this.stats.sessions.set(session.id, session);
|
|
87
|
+
}
|
|
88
|
+
trackToolCall(toolName) {
|
|
89
|
+
const existing = this.stats.toolInvocations.get(toolName) ?? { count: 0, lastUsed: 0 };
|
|
90
|
+
existing.count++;
|
|
91
|
+
existing.lastUsed = Date.now();
|
|
92
|
+
this.stats.toolInvocations.set(toolName, existing);
|
|
93
|
+
}
|
|
94
|
+
trackChannel(name, connected, messages) {
|
|
95
|
+
const existing = this.stats.channelStats.get(name) ?? { connected: false, messages: 0 };
|
|
96
|
+
existing.connected = connected;
|
|
97
|
+
if (messages !== undefined)
|
|
98
|
+
existing.messages = messages;
|
|
99
|
+
this.stats.channelStats.set(name, existing);
|
|
100
|
+
}
|
|
101
|
+
// ─── Lifecycle ───────────────────────────────────────────
|
|
102
|
+
async start() {
|
|
103
|
+
if (!this.config.enabled)
|
|
104
|
+
return;
|
|
105
|
+
return new Promise((resolve) => {
|
|
106
|
+
this.server = this.app.listen(this.config.port, this.config.host, () => {
|
|
107
|
+
console.log(`[dashboard] http://${this.config.host}:${this.config.port}`);
|
|
108
|
+
resolve();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async stop() {
|
|
113
|
+
return new Promise((resolve) => {
|
|
114
|
+
if (this.server)
|
|
115
|
+
this.server.close(() => resolve());
|
|
116
|
+
else
|
|
117
|
+
resolve();
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
renderHTML() {
|
|
121
|
+
return `<!DOCTYPE html>
|
|
122
|
+
<html><head><meta charset="utf-8"><title>OPC Agent Dashboard</title>
|
|
123
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
124
|
+
<style>
|
|
125
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
126
|
+
body{font-family:system-ui,-apple-system,sans-serif;background:#0a0a0f;color:#e0e0e0;padding:24px}
|
|
127
|
+
h1{font-size:1.5rem;margin-bottom:20px;color:#7c9aff}
|
|
128
|
+
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
|
|
129
|
+
.card{background:#14141f;border:1px solid #2a2a3a;border-radius:12px;padding:20px}
|
|
130
|
+
.card h2{font-size:0.85rem;text-transform:uppercase;letter-spacing:1px;color:#888;margin-bottom:12px}
|
|
131
|
+
.stat{font-size:2rem;font-weight:700;color:#7c9aff}
|
|
132
|
+
.sub{font-size:0.8rem;color:#666;margin-top:4px}
|
|
133
|
+
#data{margin-top:20px;font-family:monospace;font-size:0.75rem;color:#555;white-space:pre-wrap}
|
|
134
|
+
</style></head><body>
|
|
135
|
+
<h1>⚡ OPC Agent Dashboard</h1>
|
|
136
|
+
<div class="grid">
|
|
137
|
+
<div class="card"><h2>Status</h2><div class="stat" id="status">Loading…</div><div class="sub" id="uptime"></div></div>
|
|
138
|
+
<div class="card"><h2>Sessions</h2><div class="stat" id="sessions">-</div></div>
|
|
139
|
+
<div class="card"><h2>Tools</h2><div class="stat" id="tools">-</div></div>
|
|
140
|
+
<div class="card"><h2>Channels</h2><div class="stat" id="channels">-</div></div>
|
|
141
|
+
</div>
|
|
142
|
+
<div id="data"></div>
|
|
143
|
+
<script>
|
|
144
|
+
async function poll(){try{const r=await fetch('/api/state');const d=await r.json();
|
|
145
|
+
document.getElementById('status').textContent=d.agent.status;
|
|
146
|
+
document.getElementById('uptime').textContent='Uptime: '+Math.floor(d.agent.uptime/1000)+'s';
|
|
147
|
+
document.getElementById('sessions').textContent=d.sessions.length;
|
|
148
|
+
document.getElementById('tools').textContent=d.tools.length;
|
|
149
|
+
document.getElementById('channels').textContent=d.channels.length;
|
|
150
|
+
document.getElementById('data').textContent=JSON.stringify(d,null,2);
|
|
151
|
+
}catch(e){document.getElementById('status').textContent='offline'}}
|
|
152
|
+
poll();setInterval(poll,5000);
|
|
153
|
+
</script></body></html>`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.Dashboard = Dashboard;
|
|
157
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface PriorityConfig {
|
|
2
|
+
/** Enable priority mode (default: false) */
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
/** Provider-specific priority settings */
|
|
5
|
+
providers?: PriorityProviderConfig[];
|
|
6
|
+
/** Default priority tier */
|
|
7
|
+
defaultTier?: PriorityTier;
|
|
8
|
+
}
|
|
9
|
+
export type PriorityTier = 'standard' | 'fast' | 'batch';
|
|
10
|
+
export interface PriorityProviderConfig {
|
|
11
|
+
provider: string;
|
|
12
|
+
tier: PriorityTier;
|
|
13
|
+
/** Custom endpoint override for priority routing */
|
|
14
|
+
endpoint?: string;
|
|
15
|
+
/** Supported models for this tier */
|
|
16
|
+
models?: string[];
|
|
17
|
+
}
|
|
18
|
+
interface PriorityHeaders {
|
|
19
|
+
[key: string]: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class PriorityRouter {
|
|
22
|
+
private config;
|
|
23
|
+
private runtimeTier;
|
|
24
|
+
constructor(config: PriorityConfig);
|
|
25
|
+
/** Toggle fast mode on/off at runtime */
|
|
26
|
+
toggle(): PriorityTier;
|
|
27
|
+
/** Set specific tier */
|
|
28
|
+
setTier(tier: PriorityTier): void;
|
|
29
|
+
/** Get current tier */
|
|
30
|
+
getTier(): PriorityTier;
|
|
31
|
+
/** Check if fast mode is active */
|
|
32
|
+
isFast(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get priority headers for a provider + model combination.
|
|
35
|
+
* Returns empty object if provider doesn't support priority or model isn't eligible.
|
|
36
|
+
*/
|
|
37
|
+
getHeaders(provider: string, model: string): PriorityHeaders;
|
|
38
|
+
/**
|
|
39
|
+
* Get effective endpoint for a provider, allowing priority-specific routing.
|
|
40
|
+
*/
|
|
41
|
+
getEndpoint(provider: string, defaultEndpoint: string): string;
|
|
42
|
+
private getEffectiveTier;
|
|
43
|
+
private isModelEligible;
|
|
44
|
+
/** Status summary for dashboard / CLI */
|
|
45
|
+
status(): {
|
|
46
|
+
tier: PriorityTier;
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
providers: string[];
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=priority.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── Priority / Fast Mode ────────────────────────────────────
|
|
3
|
+
// Route requests through provider priority tiers for lower latency.
|
|
4
|
+
// Toggle via config or runtime command.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PriorityRouter = void 0;
|
|
7
|
+
// Known priority-capable providers and their routing
|
|
8
|
+
const PROVIDER_PRIORITY_MAP = {
|
|
9
|
+
openai: {
|
|
10
|
+
headerKey: 'X-OpenAI-Processing-Priority',
|
|
11
|
+
headerValue: { fast: 'priority', standard: 'auto', batch: 'batch' },
|
|
12
|
+
supportedModels: ['gpt-5', 'gpt-5.4', 'gpt-4.1', 'codex-*', 'o3-*', 'o4-mini*'],
|
|
13
|
+
},
|
|
14
|
+
anthropic: {
|
|
15
|
+
headerKey: 'anthropic-priority',
|
|
16
|
+
headerValue: { fast: 'high', standard: 'normal', batch: 'low' },
|
|
17
|
+
supportedModels: ['claude-opus-*', 'claude-sonnet-*', 'claude-4*'],
|
|
18
|
+
},
|
|
19
|
+
google: {
|
|
20
|
+
headerKey: 'X-Goog-Priority',
|
|
21
|
+
headerValue: { fast: 'high', standard: 'normal', batch: 'low' },
|
|
22
|
+
supportedModels: ['gemini-2.5-*', 'gemini-3-*'],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
class PriorityRouter {
|
|
26
|
+
config;
|
|
27
|
+
runtimeTier;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.runtimeTier = config.defaultTier ?? 'standard';
|
|
31
|
+
}
|
|
32
|
+
/** Toggle fast mode on/off at runtime */
|
|
33
|
+
toggle() {
|
|
34
|
+
this.runtimeTier = this.runtimeTier === 'fast' ? 'standard' : 'fast';
|
|
35
|
+
return this.runtimeTier;
|
|
36
|
+
}
|
|
37
|
+
/** Set specific tier */
|
|
38
|
+
setTier(tier) {
|
|
39
|
+
this.runtimeTier = tier;
|
|
40
|
+
}
|
|
41
|
+
/** Get current tier */
|
|
42
|
+
getTier() {
|
|
43
|
+
return this.runtimeTier;
|
|
44
|
+
}
|
|
45
|
+
/** Check if fast mode is active */
|
|
46
|
+
isFast() {
|
|
47
|
+
return this.runtimeTier === 'fast';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get priority headers for a provider + model combination.
|
|
51
|
+
* Returns empty object if provider doesn't support priority or model isn't eligible.
|
|
52
|
+
*/
|
|
53
|
+
getHeaders(provider, model) {
|
|
54
|
+
if (!this.config.enabled)
|
|
55
|
+
return {};
|
|
56
|
+
const tier = this.getEffectiveTier(provider);
|
|
57
|
+
if (tier === 'standard')
|
|
58
|
+
return {};
|
|
59
|
+
const providerMap = PROVIDER_PRIORITY_MAP[provider.toLowerCase()];
|
|
60
|
+
if (!providerMap)
|
|
61
|
+
return {};
|
|
62
|
+
// Check model eligibility
|
|
63
|
+
if (!this.isModelEligible(providerMap.supportedModels, model))
|
|
64
|
+
return {};
|
|
65
|
+
return { [providerMap.headerKey]: providerMap.headerValue[tier] };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get effective endpoint for a provider, allowing priority-specific routing.
|
|
69
|
+
*/
|
|
70
|
+
getEndpoint(provider, defaultEndpoint) {
|
|
71
|
+
const providerConfig = this.config.providers?.find((p) => p.provider.toLowerCase() === provider.toLowerCase());
|
|
72
|
+
if (providerConfig?.endpoint && this.runtimeTier === 'fast') {
|
|
73
|
+
return providerConfig.endpoint;
|
|
74
|
+
}
|
|
75
|
+
return defaultEndpoint;
|
|
76
|
+
}
|
|
77
|
+
getEffectiveTier(provider) {
|
|
78
|
+
// Check provider-specific override first
|
|
79
|
+
const providerConfig = this.config.providers?.find((p) => p.provider.toLowerCase() === provider.toLowerCase());
|
|
80
|
+
if (providerConfig)
|
|
81
|
+
return providerConfig.tier;
|
|
82
|
+
return this.runtimeTier;
|
|
83
|
+
}
|
|
84
|
+
isModelEligible(patterns, model) {
|
|
85
|
+
return patterns.some((pattern) => {
|
|
86
|
+
if (pattern.endsWith('*')) {
|
|
87
|
+
return model.startsWith(pattern.slice(0, -1));
|
|
88
|
+
}
|
|
89
|
+
return model === pattern;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/** Status summary for dashboard / CLI */
|
|
93
|
+
status() {
|
|
94
|
+
return {
|
|
95
|
+
tier: this.runtimeTier,
|
|
96
|
+
enabled: this.config.enabled,
|
|
97
|
+
providers: Object.keys(PROVIDER_PRIORITY_MAP),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.PriorityRouter = PriorityRouter;
|
|
102
|
+
//# sourceMappingURL=priority.js.map
|
package/dist/deploy/hermes.js
CHANGED
|
@@ -113,32 +113,32 @@ function deployToHermes(options) {
|
|
|
113
113
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
114
114
|
files.push('settings.json');
|
|
115
115
|
// .env template
|
|
116
|
-
const envContent = `# Hermes Agent Environment
|
|
117
|
-
HERMES_CHARACTER=${oad.metadata.name}
|
|
118
|
-
HERMES_MODEL=${oad.spec.model}
|
|
119
|
-
HERMES_PROVIDER=${oad.spec.provider?.default ?? 'openai'}
|
|
120
|
-
# Add your API keys below:
|
|
121
|
-
# OPENAI_API_KEY=
|
|
122
|
-
# DEEPSEEK_API_KEY=
|
|
116
|
+
const envContent = `# Hermes Agent Environment
|
|
117
|
+
HERMES_CHARACTER=${oad.metadata.name}
|
|
118
|
+
HERMES_MODEL=${oad.spec.model}
|
|
119
|
+
HERMES_PROVIDER=${oad.spec.provider?.default ?? 'openai'}
|
|
120
|
+
# Add your API keys below:
|
|
121
|
+
# OPENAI_API_KEY=
|
|
122
|
+
# DEEPSEEK_API_KEY=
|
|
123
123
|
`;
|
|
124
124
|
fs.writeFileSync(path.join(outputDir, '.env.hermes'), envContent, 'utf-8');
|
|
125
125
|
files.push('.env.hermes');
|
|
126
126
|
// README
|
|
127
|
-
const readme = `# ${oad.metadata.name} - Hermes Agent
|
|
128
|
-
|
|
129
|
-
Converted from OAD format using \`opc deploy --target hermes\`.
|
|
130
|
-
|
|
131
|
-
## Usage
|
|
132
|
-
|
|
133
|
-
1. Copy \`character.json\` to your Hermes agents directory
|
|
134
|
-
2. Configure \`.env.hermes\` with your API keys
|
|
135
|
-
3. Start Hermes with this character
|
|
136
|
-
|
|
137
|
-
## Files
|
|
138
|
-
|
|
139
|
-
- \`character.json\` - Agent character definition
|
|
140
|
-
- \`settings.json\` - Runtime settings
|
|
141
|
-
- \`.env.hermes\` - Environment template
|
|
127
|
+
const readme = `# ${oad.metadata.name} - Hermes Agent
|
|
128
|
+
|
|
129
|
+
Converted from OAD format using \`opc deploy --target hermes\`.
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
|
|
133
|
+
1. Copy \`character.json\` to your Hermes agents directory
|
|
134
|
+
2. Configure \`.env.hermes\` with your API keys
|
|
135
|
+
3. Start Hermes with this character
|
|
136
|
+
|
|
137
|
+
## Files
|
|
138
|
+
|
|
139
|
+
- \`character.json\` - Agent character definition
|
|
140
|
+
- \`settings.json\` - Runtime settings
|
|
141
|
+
- \`.env.hermes\` - Environment template
|
|
142
142
|
`;
|
|
143
143
|
fs.writeFileSync(path.join(outputDir, 'README.md'), readme, 'utf-8');
|
|
144
144
|
files.push('README.md');
|
package/dist/deploy/openclaw.js
CHANGED
|
@@ -41,27 +41,27 @@ const fs = __importStar(require("fs"));
|
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
function generateIdentityMd(oad) {
|
|
43
43
|
const m = oad.metadata;
|
|
44
|
-
return `# IDENTITY.md
|
|
45
|
-
|
|
46
|
-
- **Name:** ${m.name}
|
|
47
|
-
- **Version:** ${m.version}
|
|
48
|
-
- **Description:** ${m.description ?? 'An AI agent'}
|
|
49
|
-
- **Author:** ${m.author ?? 'Unknown'}
|
|
50
|
-
- **License:** ${m.license}
|
|
44
|
+
return `# IDENTITY.md
|
|
45
|
+
|
|
46
|
+
- **Name:** ${m.name}
|
|
47
|
+
- **Version:** ${m.version}
|
|
48
|
+
- **Description:** ${m.description ?? 'An AI agent'}
|
|
49
|
+
- **Author:** ${m.author ?? 'Unknown'}
|
|
50
|
+
- **License:** ${m.license}
|
|
51
51
|
`;
|
|
52
52
|
}
|
|
53
53
|
function generateSoulMd(oad) {
|
|
54
54
|
const prompt = oad.spec.systemPrompt ?? 'You are a helpful AI assistant.';
|
|
55
|
-
return `# SOUL.md - ${oad.metadata.name}
|
|
56
|
-
|
|
57
|
-
## System Prompt
|
|
58
|
-
|
|
59
|
-
${prompt}
|
|
60
|
-
|
|
61
|
-
## Model Configuration
|
|
62
|
-
|
|
63
|
-
- **Model:** ${oad.spec.model}
|
|
64
|
-
- **Provider:** ${oad.spec.provider?.default ?? 'deepseek'}
|
|
55
|
+
return `# SOUL.md - ${oad.metadata.name}
|
|
56
|
+
|
|
57
|
+
## System Prompt
|
|
58
|
+
|
|
59
|
+
${prompt}
|
|
60
|
+
|
|
61
|
+
## Model Configuration
|
|
62
|
+
|
|
63
|
+
- **Model:** ${oad.spec.model}
|
|
64
|
+
- **Provider:** ${oad.spec.provider?.default ?? 'deepseek'}
|
|
65
65
|
`;
|
|
66
66
|
}
|
|
67
67
|
function generateAgentsMd(oad) {
|
|
@@ -100,26 +100,35 @@ function generateAgentsMd(oad) {
|
|
|
100
100
|
md += `Default memory settings.\n`;
|
|
101
101
|
}
|
|
102
102
|
md += `\n`;
|
|
103
|
+
// DTV
|
|
104
|
+
if (dtv) {
|
|
105
|
+
md += `## Trust & Value\n\n`;
|
|
106
|
+
md += `- Trust Level: ${dtv.trust?.level ?? 'sandbox'}\n`;
|
|
107
|
+
if (dtv.value?.metrics?.length) {
|
|
108
|
+
md += `- Metrics: ${dtv.value.metrics.join(', ')}\n`;
|
|
109
|
+
}
|
|
110
|
+
md += `\n`;
|
|
111
|
+
}
|
|
103
112
|
return md;
|
|
104
113
|
}
|
|
105
114
|
function generateUserMd(oad) {
|
|
106
|
-
return `# USER.md
|
|
107
|
-
|
|
108
|
-
- **Name:** (your name)
|
|
109
|
-
- **Role:** User
|
|
110
|
-
- **Notes:** Configure this file with your preferences for ${oad.metadata.name}.
|
|
115
|
+
return `# USER.md
|
|
116
|
+
|
|
117
|
+
- **Name:** (your name)
|
|
118
|
+
- **Role:** User
|
|
119
|
+
- **Notes:** Configure this file with your preferences for ${oad.metadata.name}.
|
|
111
120
|
`;
|
|
112
121
|
}
|
|
113
122
|
function generateMemoryMd(oad) {
|
|
114
|
-
return `# MEMORY.md - ${oad.metadata.name}
|
|
115
|
-
|
|
116
|
-
## Persistent Knowledge
|
|
117
|
-
|
|
118
|
-
(Agent will store learned information here)
|
|
119
|
-
|
|
120
|
-
## User Preferences
|
|
121
|
-
|
|
122
|
-
(Discovered user preferences will be noted here)
|
|
123
|
+
return `# MEMORY.md - ${oad.metadata.name}
|
|
124
|
+
|
|
125
|
+
## Persistent Knowledge
|
|
126
|
+
|
|
127
|
+
(Agent will store learned information here)
|
|
128
|
+
|
|
129
|
+
## User Preferences
|
|
130
|
+
|
|
131
|
+
(Discovered user preferences will be noted here)
|
|
123
132
|
`;
|
|
124
133
|
}
|
|
125
134
|
function generateOpenClawConfig(oad, agentDir) {
|