opc-agent 0.5.1 → 0.7.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/channels/web.d.ts +14 -1
- package/dist/channels/web.js +289 -3
- package/dist/cli.js +135 -4
- package/dist/core/auth.d.ts +13 -0
- package/dist/core/auth.js +41 -0
- package/dist/core/knowledge.d.ts +28 -0
- package/dist/core/knowledge.js +212 -0
- package/dist/deploy/hermes.d.ts +11 -0
- package/dist/deploy/hermes.js +147 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +21 -1
- package/dist/marketplace/index.d.ts +34 -0
- package/dist/marketplace/index.js +202 -0
- package/dist/schema/oad.d.ts +69 -0
- package/dist/schema/oad.js +7 -1
- package/dist/skills/document.d.ts +27 -0
- package/dist/skills/document.js +80 -0
- package/dist/skills/http.d.ts +8 -0
- package/dist/skills/http.js +34 -0
- package/dist/skills/scheduler.d.ts +21 -0
- package/dist/skills/scheduler.js +70 -0
- package/dist/skills/webhook-trigger.d.ts +17 -0
- package/dist/skills/webhook-trigger.js +49 -0
- package/package.json +1 -1
- package/src/channels/web.ts +302 -3
- package/src/cli.ts +149 -4
- package/src/core/auth.ts +57 -0
- package/src/core/knowledge.ts +210 -0
- package/src/deploy/hermes.ts +156 -0
- package/src/index.ts +18 -0
- package/src/marketplace/index.ts +223 -0
- package/src/schema/oad.ts +7 -0
- package/src/skills/document.ts +100 -0
- package/src/skills/http.ts +35 -0
- package/src/skills/scheduler.ts +80 -0
- package/src/skills/webhook-trigger.ts +59 -0
- package/templates/Dockerfile +15 -0
- package/templates/docker-compose.yml +21 -0
- package/tests/v070.test.ts +76 -0
package/dist/schema/oad.d.ts
CHANGED
|
@@ -77,6 +77,19 @@ export declare const HITLSchema: z.ZodObject<{
|
|
|
77
77
|
defaultTimeoutMs?: number | undefined;
|
|
78
78
|
defaultAction?: "approve" | "deny" | undefined;
|
|
79
79
|
}>;
|
|
80
|
+
export declare const AuthSchema: z.ZodObject<{
|
|
81
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
82
|
+
apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
83
|
+
sessionIsolation: z.ZodDefault<z.ZodBoolean>;
|
|
84
|
+
}, "strip", z.ZodTypeAny, {
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
apiKeys: string[];
|
|
87
|
+
sessionIsolation: boolean;
|
|
88
|
+
}, {
|
|
89
|
+
enabled?: boolean | undefined;
|
|
90
|
+
apiKeys?: string[] | undefined;
|
|
91
|
+
sessionIsolation?: boolean | undefined;
|
|
92
|
+
}>;
|
|
80
93
|
export declare const ChannelSchema: z.ZodObject<{
|
|
81
94
|
type: z.ZodEnum<["web", "websocket", "telegram", "cli", "voice", "webhook"]>;
|
|
82
95
|
port: z.ZodOptional<z.ZodNumber>;
|
|
@@ -453,6 +466,19 @@ export declare const SpecSchema: z.ZodObject<{
|
|
|
453
466
|
defaultTimeoutMs?: number | undefined;
|
|
454
467
|
defaultAction?: "approve" | "deny" | undefined;
|
|
455
468
|
}>>;
|
|
469
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
470
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
471
|
+
apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
472
|
+
sessionIsolation: z.ZodDefault<z.ZodBoolean>;
|
|
473
|
+
}, "strip", z.ZodTypeAny, {
|
|
474
|
+
enabled: boolean;
|
|
475
|
+
apiKeys: string[];
|
|
476
|
+
sessionIsolation: boolean;
|
|
477
|
+
}, {
|
|
478
|
+
enabled?: boolean | undefined;
|
|
479
|
+
apiKeys?: string[] | undefined;
|
|
480
|
+
sessionIsolation?: boolean | undefined;
|
|
481
|
+
}>>;
|
|
456
482
|
}, "strip", z.ZodTypeAny, {
|
|
457
483
|
model: string;
|
|
458
484
|
skills: {
|
|
@@ -469,6 +495,11 @@ export declare const SpecSchema: z.ZodObject<{
|
|
|
469
495
|
enabled: boolean;
|
|
470
496
|
chunkSize?: number | undefined;
|
|
471
497
|
};
|
|
498
|
+
auth?: {
|
|
499
|
+
enabled: boolean;
|
|
500
|
+
apiKeys: string[];
|
|
501
|
+
sessionIsolation: boolean;
|
|
502
|
+
} | undefined;
|
|
472
503
|
voice?: {
|
|
473
504
|
enabled: boolean;
|
|
474
505
|
sttProvider?: string | undefined;
|
|
@@ -522,6 +553,11 @@ export declare const SpecSchema: z.ZodObject<{
|
|
|
522
553
|
defaultAction: "approve" | "deny";
|
|
523
554
|
} | undefined;
|
|
524
555
|
}, {
|
|
556
|
+
auth?: {
|
|
557
|
+
enabled?: boolean | undefined;
|
|
558
|
+
apiKeys?: string[] | undefined;
|
|
559
|
+
sessionIsolation?: boolean | undefined;
|
|
560
|
+
} | undefined;
|
|
525
561
|
voice?: {
|
|
526
562
|
enabled?: boolean | undefined;
|
|
527
563
|
sttProvider?: string | undefined;
|
|
@@ -830,6 +866,19 @@ export declare const OADSchema: z.ZodObject<{
|
|
|
830
866
|
defaultTimeoutMs?: number | undefined;
|
|
831
867
|
defaultAction?: "approve" | "deny" | undefined;
|
|
832
868
|
}>>;
|
|
869
|
+
auth: z.ZodOptional<z.ZodObject<{
|
|
870
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
871
|
+
apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
872
|
+
sessionIsolation: z.ZodDefault<z.ZodBoolean>;
|
|
873
|
+
}, "strip", z.ZodTypeAny, {
|
|
874
|
+
enabled: boolean;
|
|
875
|
+
apiKeys: string[];
|
|
876
|
+
sessionIsolation: boolean;
|
|
877
|
+
}, {
|
|
878
|
+
enabled?: boolean | undefined;
|
|
879
|
+
apiKeys?: string[] | undefined;
|
|
880
|
+
sessionIsolation?: boolean | undefined;
|
|
881
|
+
}>>;
|
|
833
882
|
}, "strip", z.ZodTypeAny, {
|
|
834
883
|
model: string;
|
|
835
884
|
skills: {
|
|
@@ -846,6 +895,11 @@ export declare const OADSchema: z.ZodObject<{
|
|
|
846
895
|
enabled: boolean;
|
|
847
896
|
chunkSize?: number | undefined;
|
|
848
897
|
};
|
|
898
|
+
auth?: {
|
|
899
|
+
enabled: boolean;
|
|
900
|
+
apiKeys: string[];
|
|
901
|
+
sessionIsolation: boolean;
|
|
902
|
+
} | undefined;
|
|
849
903
|
voice?: {
|
|
850
904
|
enabled: boolean;
|
|
851
905
|
sttProvider?: string | undefined;
|
|
@@ -899,6 +953,11 @@ export declare const OADSchema: z.ZodObject<{
|
|
|
899
953
|
defaultAction: "approve" | "deny";
|
|
900
954
|
} | undefined;
|
|
901
955
|
}, {
|
|
956
|
+
auth?: {
|
|
957
|
+
enabled?: boolean | undefined;
|
|
958
|
+
apiKeys?: string[] | undefined;
|
|
959
|
+
sessionIsolation?: boolean | undefined;
|
|
960
|
+
} | undefined;
|
|
902
961
|
voice?: {
|
|
903
962
|
enabled?: boolean | undefined;
|
|
904
963
|
sttProvider?: string | undefined;
|
|
@@ -999,6 +1058,11 @@ export declare const OADSchema: z.ZodObject<{
|
|
|
999
1058
|
enabled: boolean;
|
|
1000
1059
|
chunkSize?: number | undefined;
|
|
1001
1060
|
};
|
|
1061
|
+
auth?: {
|
|
1062
|
+
enabled: boolean;
|
|
1063
|
+
apiKeys: string[];
|
|
1064
|
+
sessionIsolation: boolean;
|
|
1065
|
+
} | undefined;
|
|
1002
1066
|
voice?: {
|
|
1003
1067
|
enabled: boolean;
|
|
1004
1068
|
sttProvider?: string | undefined;
|
|
@@ -1069,6 +1133,11 @@ export declare const OADSchema: z.ZodObject<{
|
|
|
1069
1133
|
} | undefined;
|
|
1070
1134
|
};
|
|
1071
1135
|
spec: {
|
|
1136
|
+
auth?: {
|
|
1137
|
+
enabled?: boolean | undefined;
|
|
1138
|
+
apiKeys?: string[] | undefined;
|
|
1139
|
+
sessionIsolation?: boolean | undefined;
|
|
1140
|
+
} | undefined;
|
|
1072
1141
|
voice?: {
|
|
1073
1142
|
enabled?: boolean | undefined;
|
|
1074
1143
|
sttProvider?: string | undefined;
|
package/dist/schema/oad.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OADSchema = exports.SpecSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
|
|
3
|
+
exports.OADSchema = exports.SpecSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.AuthSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
// ─── OAD Schema v1 ───────────────────────────────────────────
|
|
6
6
|
exports.SkillRefSchema = zod_1.z.object({
|
|
@@ -43,6 +43,11 @@ exports.HITLSchema = zod_1.z.object({
|
|
|
43
43
|
defaultTimeoutMs: zod_1.z.number().default(60000),
|
|
44
44
|
defaultAction: zod_1.z.enum(['approve', 'deny']).default('deny'),
|
|
45
45
|
});
|
|
46
|
+
exports.AuthSchema = zod_1.z.object({
|
|
47
|
+
enabled: zod_1.z.boolean().default(false),
|
|
48
|
+
apiKeys: zod_1.z.array(zod_1.z.string()).default([]),
|
|
49
|
+
sessionIsolation: zod_1.z.boolean().default(true),
|
|
50
|
+
});
|
|
46
51
|
exports.ChannelSchema = zod_1.z.object({
|
|
47
52
|
type: zod_1.z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook']),
|
|
48
53
|
port: zod_1.z.number().optional(),
|
|
@@ -109,6 +114,7 @@ exports.SpecSchema = zod_1.z.object({
|
|
|
109
114
|
voice: exports.VoiceSchema.optional(),
|
|
110
115
|
webhook: exports.WebhookSchema.optional(),
|
|
111
116
|
hitl: exports.HITLSchema.optional(),
|
|
117
|
+
auth: exports.AuthSchema.optional(),
|
|
112
118
|
});
|
|
113
119
|
exports.OADSchema = zod_1.z.object({
|
|
114
120
|
apiVersion: zod_1.z.literal('opc/v1'),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseSkill } from './base';
|
|
2
|
+
import type { AgentContext, Message, SkillResult } from '../core/types';
|
|
3
|
+
export interface DocumentChunk {
|
|
4
|
+
content: string;
|
|
5
|
+
metadata: {
|
|
6
|
+
filename: string;
|
|
7
|
+
mimeType: string;
|
|
8
|
+
chunkIndex: number;
|
|
9
|
+
totalChunks: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare class DocumentSkill extends BaseSkill {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
private knowledgeBase;
|
|
16
|
+
constructor(kbPath?: string);
|
|
17
|
+
execute(context: AgentContext, message: Message): Promise<SkillResult>;
|
|
18
|
+
extractText(content: string, mimeType: string): string;
|
|
19
|
+
chunk(text: string, size?: number, overlap?: number): DocumentChunk[];
|
|
20
|
+
private guessMime;
|
|
21
|
+
/** Process raw text content directly (for API uploads) */
|
|
22
|
+
processText(content: string, filename: string): Promise<{
|
|
23
|
+
chunks: number;
|
|
24
|
+
chars: number;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DocumentSkill = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const knowledge_1 = require("../core/knowledge");
|
|
6
|
+
class DocumentSkill extends base_1.BaseSkill {
|
|
7
|
+
name = 'document';
|
|
8
|
+
description = 'Process uploaded documents (PDF, TXT, MD, DOCX). Chunks content and adds to knowledge base.';
|
|
9
|
+
knowledgeBase;
|
|
10
|
+
constructor(kbPath = '.') {
|
|
11
|
+
super();
|
|
12
|
+
this.knowledgeBase = new knowledge_1.KnowledgeBase(kbPath);
|
|
13
|
+
}
|
|
14
|
+
async execute(context, message) {
|
|
15
|
+
// Check if message has document attachment metadata
|
|
16
|
+
const meta = message.metadata;
|
|
17
|
+
if (!meta?.document)
|
|
18
|
+
return this.noMatch();
|
|
19
|
+
const { content, filename, mimeType } = meta.document;
|
|
20
|
+
try {
|
|
21
|
+
const text = this.extractText(content, mimeType ?? this.guessMime(filename));
|
|
22
|
+
const chunks = this.chunk(text, 1000, 100);
|
|
23
|
+
const result = await this.knowledgeBase.addText(chunks.map(c => c.content).join('\n\n---\n\n'), filename);
|
|
24
|
+
return this.match(`📄 Processed "${filename}": ${chunks.length} chunks, ${text.length} chars → added to knowledge base (${result.chunks} KB entries)`);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return this.match(`Document processing error: ${err instanceof Error ? err.message : String(err)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
extractText(content, mimeType) {
|
|
31
|
+
// For plain text formats, content is already text
|
|
32
|
+
if (mimeType.includes('text/') || mimeType.includes('markdown')) {
|
|
33
|
+
return content;
|
|
34
|
+
}
|
|
35
|
+
// For other formats, assume base64-encoded or pre-extracted text
|
|
36
|
+
// In a real implementation, you'd use pdf-parse, mammoth, etc.
|
|
37
|
+
return content;
|
|
38
|
+
}
|
|
39
|
+
chunk(text, size = 1000, overlap = 100) {
|
|
40
|
+
const chunks = [];
|
|
41
|
+
let start = 0;
|
|
42
|
+
while (start < text.length) {
|
|
43
|
+
const end = Math.min(start + size, text.length);
|
|
44
|
+
chunks.push({
|
|
45
|
+
content: text.slice(start, end),
|
|
46
|
+
metadata: {
|
|
47
|
+
filename: '',
|
|
48
|
+
mimeType: '',
|
|
49
|
+
chunkIndex: chunks.length,
|
|
50
|
+
totalChunks: 0, // filled after
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
start = end - overlap;
|
|
54
|
+
if (start >= text.length)
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
// Fill totalChunks
|
|
58
|
+
for (const c of chunks)
|
|
59
|
+
c.metadata.totalChunks = chunks.length;
|
|
60
|
+
return chunks;
|
|
61
|
+
}
|
|
62
|
+
guessMime(filename) {
|
|
63
|
+
const ext = filename.split('.').pop()?.toLowerCase();
|
|
64
|
+
switch (ext) {
|
|
65
|
+
case 'pdf': return 'application/pdf';
|
|
66
|
+
case 'txt': return 'text/plain';
|
|
67
|
+
case 'md': return 'text/markdown';
|
|
68
|
+
case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
69
|
+
default: return 'text/plain';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Process raw text content directly (for API uploads) */
|
|
73
|
+
async processText(content, filename) {
|
|
74
|
+
const chunks = this.chunk(content);
|
|
75
|
+
const result = await this.knowledgeBase.addText(content, filename);
|
|
76
|
+
return { chunks: chunks.length, chars: content.length };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.DocumentSkill = DocumentSkill;
|
|
80
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseSkill } from './base';
|
|
2
|
+
import type { AgentContext, Message, SkillResult } from '../core/types';
|
|
3
|
+
export declare class HttpSkill extends BaseSkill {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
execute(context: AgentContext, message: Message): Promise<SkillResult>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpSkill = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
class HttpSkill extends base_1.BaseSkill {
|
|
6
|
+
name = 'http';
|
|
7
|
+
description = 'Make HTTP requests to external APIs. Usage: http GET|POST|PUT|DELETE <url> [body]';
|
|
8
|
+
async execute(context, message) {
|
|
9
|
+
const text = message.content.trim();
|
|
10
|
+
const match = text.match(/^http\s+(GET|POST|PUT|PATCH|DELETE)\s+(\S+)(?:\s+(.+))?$/is);
|
|
11
|
+
if (!match)
|
|
12
|
+
return this.noMatch();
|
|
13
|
+
const [, method, url, bodyStr] = match;
|
|
14
|
+
try {
|
|
15
|
+
const opts = {
|
|
16
|
+
method: method.toUpperCase(),
|
|
17
|
+
headers: { 'Content-Type': 'application/json', 'User-Agent': 'OPC-Agent/0.7.0' },
|
|
18
|
+
};
|
|
19
|
+
if (bodyStr && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
|
|
20
|
+
opts.body = bodyStr;
|
|
21
|
+
}
|
|
22
|
+
const res = await fetch(url, opts);
|
|
23
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
24
|
+
const body = contentType.includes('json') ? JSON.stringify(await res.json(), null, 2) : await res.text();
|
|
25
|
+
const truncated = body.length > 4000 ? body.slice(0, 4000) + '\n...[truncated]' : body;
|
|
26
|
+
return this.match(`HTTP ${res.status} ${res.statusText}\n\n${truncated}`);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return this.match(`HTTP Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.HttpSkill = HttpSkill;
|
|
34
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseSkill } from './base';
|
|
2
|
+
import type { AgentContext, Message, SkillResult } from '../core/types';
|
|
3
|
+
export interface ScheduledTask {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
cronExpr: string;
|
|
7
|
+
action: string;
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
lastRun?: number;
|
|
10
|
+
nextRun?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class SchedulerSkill extends BaseSkill {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
private tasks;
|
|
16
|
+
private timers;
|
|
17
|
+
execute(context: AgentContext, message: Message): Promise<SkillResult>;
|
|
18
|
+
private parseCronToInterval;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchedulerSkill = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
class SchedulerSkill extends base_1.BaseSkill {
|
|
6
|
+
name = 'scheduler';
|
|
7
|
+
description = 'Schedule recurring tasks. Usage: schedule list | schedule add <name> <cron> <action> | schedule remove <id>';
|
|
8
|
+
tasks = new Map();
|
|
9
|
+
timers = new Map();
|
|
10
|
+
async execute(context, message) {
|
|
11
|
+
const text = message.content.trim();
|
|
12
|
+
if (/^schedule\s+list$/i.test(text)) {
|
|
13
|
+
if (this.tasks.size === 0)
|
|
14
|
+
return this.match('No scheduled tasks.');
|
|
15
|
+
const lines = Array.from(this.tasks.values()).map(t => `• ${t.name} (${t.id}) — ${t.cronExpr} — ${t.enabled ? '✅' : '❌'} — Last: ${t.lastRun ? new Date(t.lastRun).toISOString() : 'never'}`);
|
|
16
|
+
return this.match(`Scheduled tasks:\n${lines.join('\n')}`);
|
|
17
|
+
}
|
|
18
|
+
const addMatch = text.match(/^schedule\s+add\s+(\S+)\s+(".*?"|\S+)\s+(.+)$/i);
|
|
19
|
+
if (addMatch) {
|
|
20
|
+
const [, name, cronExpr, action] = addMatch;
|
|
21
|
+
const id = `task_${Date.now().toString(36)}`;
|
|
22
|
+
const task = {
|
|
23
|
+
id, name, cronExpr: cronExpr.replace(/"/g, ''), action, enabled: true,
|
|
24
|
+
};
|
|
25
|
+
this.tasks.set(id, task);
|
|
26
|
+
// Simple interval-based scheduling (parse cron for interval in minutes)
|
|
27
|
+
const intervalMs = this.parseCronToInterval(task.cronExpr);
|
|
28
|
+
if (intervalMs > 0) {
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
task.lastRun = Date.now();
|
|
31
|
+
}, intervalMs);
|
|
32
|
+
this.timers.set(id, timer);
|
|
33
|
+
}
|
|
34
|
+
return this.match(`Task scheduled: ${name} (${id}) — ${task.cronExpr} → "${action}"`);
|
|
35
|
+
}
|
|
36
|
+
const rmMatch = text.match(/^schedule\s+remove\s+(\S+)$/i);
|
|
37
|
+
if (rmMatch) {
|
|
38
|
+
const id = rmMatch[1];
|
|
39
|
+
const timer = this.timers.get(id);
|
|
40
|
+
if (timer)
|
|
41
|
+
clearInterval(timer);
|
|
42
|
+
this.timers.delete(id);
|
|
43
|
+
const removed = this.tasks.delete(id);
|
|
44
|
+
return this.match(removed ? `Task ${id} removed.` : `Task ${id} not found.`);
|
|
45
|
+
}
|
|
46
|
+
return this.noMatch();
|
|
47
|
+
}
|
|
48
|
+
parseCronToInterval(expr) {
|
|
49
|
+
// Simple: support "every Xm" or "every Xh" or basic intervals
|
|
50
|
+
const m = expr.match(/every\s+(\d+)\s*(m|min|h|hr|s|sec)/i);
|
|
51
|
+
if (m) {
|
|
52
|
+
const val = parseInt(m[1]);
|
|
53
|
+
const unit = m[2].toLowerCase();
|
|
54
|
+
if (unit.startsWith('h'))
|
|
55
|
+
return val * 3600_000;
|
|
56
|
+
if (unit.startsWith('m'))
|
|
57
|
+
return val * 60_000;
|
|
58
|
+
if (unit.startsWith('s'))
|
|
59
|
+
return val * 1000;
|
|
60
|
+
}
|
|
61
|
+
return 0; // Unknown cron format, no auto-schedule
|
|
62
|
+
}
|
|
63
|
+
destroy() {
|
|
64
|
+
for (const timer of this.timers.values())
|
|
65
|
+
clearInterval(timer);
|
|
66
|
+
this.timers.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.SchedulerSkill = SchedulerSkill;
|
|
70
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BaseSkill } from './base';
|
|
2
|
+
import type { AgentContext, Message, SkillResult } from '../core/types';
|
|
3
|
+
export interface WebhookTarget {
|
|
4
|
+
name: string;
|
|
5
|
+
url: string;
|
|
6
|
+
method?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
secret?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class WebhookTriggerSkill extends BaseSkill {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
private targets;
|
|
14
|
+
registerTarget(target: WebhookTarget): void;
|
|
15
|
+
execute(context: AgentContext, message: Message): Promise<SkillResult>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=webhook-trigger.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebhookTriggerSkill = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
class WebhookTriggerSkill extends base_1.BaseSkill {
|
|
6
|
+
name = 'webhook-trigger';
|
|
7
|
+
description = 'Trigger external webhooks. Usage: webhook <name> [payload JSON]';
|
|
8
|
+
targets = new Map();
|
|
9
|
+
registerTarget(target) {
|
|
10
|
+
this.targets.set(target.name, target);
|
|
11
|
+
}
|
|
12
|
+
async execute(context, message) {
|
|
13
|
+
const match = message.content.trim().match(/^webhook\s+(\S+)(?:\s+(.+))?$/is);
|
|
14
|
+
if (!match)
|
|
15
|
+
return this.noMatch();
|
|
16
|
+
const [, name, payloadStr] = match;
|
|
17
|
+
const target = this.targets.get(name);
|
|
18
|
+
if (!target) {
|
|
19
|
+
const available = Array.from(this.targets.keys()).join(', ') || 'none';
|
|
20
|
+
return this.match(`Unknown webhook "${name}". Available: ${available}`);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const headers = {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
'User-Agent': 'OPC-Agent/0.7.0',
|
|
26
|
+
...target.headers,
|
|
27
|
+
};
|
|
28
|
+
if (target.secret) {
|
|
29
|
+
headers['X-Webhook-Secret'] = target.secret;
|
|
30
|
+
}
|
|
31
|
+
const body = payloadStr ?? JSON.stringify({
|
|
32
|
+
agent: context.agentName,
|
|
33
|
+
timestamp: Date.now(),
|
|
34
|
+
trigger: 'manual',
|
|
35
|
+
});
|
|
36
|
+
const res = await fetch(target.url, {
|
|
37
|
+
method: target.method ?? 'POST',
|
|
38
|
+
headers,
|
|
39
|
+
body,
|
|
40
|
+
});
|
|
41
|
+
return this.match(`Webhook "${name}" triggered → ${res.status} ${res.statusText}`);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return this.match(`Webhook error: ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.WebhookTriggerSkill = WebhookTriggerSkill;
|
|
49
|
+
//# sourceMappingURL=webhook-trigger.js.map
|