opc-agent 1.4.0 → 2.0.1
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 +25 -0
- package/README.md +91 -32
- 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/telegram.d.ts +30 -9
- package/dist/channels/telegram.js +125 -33
- 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 +1127 -19
- package/dist/core/a2a.d.ts +17 -0
- package/dist/core/a2a.js +43 -1
- package/dist/core/agent.d.ts +39 -0
- package/dist/core/agent.js +228 -3
- package/dist/core/runtime.d.ts +7 -0
- package/dist/core/runtime.js +205 -2
- package/dist/core/sandbox.d.ts +26 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/scheduler.d.ts +52 -0
- package/dist/core/scheduler.js +168 -0
- package/dist/core/subagent.d.ts +28 -0
- package/dist/core/subagent.js +65 -0
- package/dist/core/workflow-graph.d.ts +93 -0
- package/dist/core/workflow-graph.js +247 -0
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.js +134 -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 +37 -6
- package/dist/index.js +75 -3
- 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/providers/index.d.ts +5 -1
- package/dist/providers/index.js +16 -9
- package/dist/publish/index.d.ts +45 -0
- package/dist/publish/index.js +350 -0
- package/dist/schema/oad.d.ts +859 -67
- package/dist/schema/oad.js +47 -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/skills/auto-learn.d.ts +28 -0
- package/dist/skills/auto-learn.js +257 -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/dist/tools/builtin/datetime.d.ts +3 -0
- package/dist/tools/builtin/datetime.js +44 -0
- package/dist/tools/builtin/file.d.ts +3 -0
- package/dist/tools/builtin/file.js +151 -0
- package/dist/tools/builtin/index.d.ts +15 -0
- package/dist/tools/builtin/index.js +30 -0
- package/dist/tools/builtin/shell.d.ts +3 -0
- package/dist/tools/builtin/shell.js +43 -0
- package/dist/tools/builtin/web.d.ts +3 -0
- package/dist/tools/builtin/web.js +37 -0
- package/dist/tools/mcp-client.d.ts +24 -0
- package/dist/tools/mcp-client.js +119 -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/telegram.ts +212 -90
- package/src/channels/websocket.ts +399 -87
- package/src/channels/wechat.ts +329 -149
- package/src/cli.ts +1201 -20
- package/src/core/a2a.ts +60 -0
- package/src/core/agent.ts +420 -152
- package/src/core/runtime.ts +174 -0
- package/src/core/sandbox.ts +143 -0
- package/src/core/scheduler.ts +187 -0
- package/src/core/subagent.ts +98 -0
- package/src/core/workflow-graph.ts +365 -0
- package/src/daemon.ts +96 -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 +65 -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/providers/index.ts +354 -339
- package/src/publish/index.ts +376 -0
- package/src/schema/oad.ts +204 -154
- package/src/security/approval.ts +131 -0
- package/src/security/index.ts +3 -0
- package/src/security/keys.ts +87 -0
- package/src/skills/auto-learn.ts +262 -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/tools/builtin/datetime.ts +41 -0
- package/src/tools/builtin/file.ts +107 -0
- package/src/tools/builtin/index.ts +28 -0
- package/src/tools/builtin/shell.ts +43 -0
- package/src/tools/builtin/web.ts +35 -0
- package/src/tools/mcp-client.ts +131 -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/auto-learn.test.ts +105 -0
- package/tests/builtin-tools.test.ts +83 -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/cli.test.ts +46 -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 +193 -0
- package/tests/telegram-discord.test.ts +60 -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
package/src/schema/oad.ts
CHANGED
|
@@ -1,154 +1,204 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
// ─── OAD Schema v1 ───────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
export const SkillRefSchema = z.object({
|
|
6
|
-
name: z.string(),
|
|
7
|
-
description: z.string().optional(),
|
|
8
|
-
config: z.record(z.unknown()).optional(),
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export const WorkflowStepSchema: z.ZodType<any> = z.lazy(() => z.object({
|
|
12
|
-
id: z.string(),
|
|
13
|
-
type: z.enum(['skill', 'tool', 'agent', 'condition', 'parallel']),
|
|
14
|
-
name: z.string(),
|
|
15
|
-
config: z.record(z.unknown()).optional(),
|
|
16
|
-
condition: z.string().optional(),
|
|
17
|
-
branches: z.object({ if: z.array(WorkflowStepSchema), else: z.array(WorkflowStepSchema).optional() }).optional(),
|
|
18
|
-
parallel: z.array(WorkflowStepSchema).optional(),
|
|
19
|
-
timeout: z.number().optional(),
|
|
20
|
-
retries: z.number().optional(),
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
export const WorkflowSchema = z.object({
|
|
24
|
-
name: z.string(),
|
|
25
|
-
description: z.string().optional(),
|
|
26
|
-
version: z.string().optional(),
|
|
27
|
-
steps: z.array(WorkflowStepSchema).default([]),
|
|
28
|
-
onError: z.enum(['stop', 'skip', 'retry']).optional(),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export const VoiceSchema = z.object({
|
|
32
|
-
enabled: z.boolean().default(false),
|
|
33
|
-
sttProvider: z.string().optional(),
|
|
34
|
-
ttsProvider: z.string().optional(),
|
|
35
|
-
language: z.string().optional(),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
export const WebhookSchema = z.object({
|
|
39
|
-
path: z.string().optional(),
|
|
40
|
-
secret: z.string().optional(),
|
|
41
|
-
retryAttempts: z.number().optional(),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export const HITLSchema = z.object({
|
|
45
|
-
enabled: z.boolean().default(false),
|
|
46
|
-
requireApproval: z.array(z.string()).default([]),
|
|
47
|
-
defaultTimeoutMs: z.number().default(60000),
|
|
48
|
-
defaultAction: z.enum(['approve', 'deny']).default('deny'),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export const PluginRefSchema = z.object({
|
|
52
|
-
name: z.string(),
|
|
53
|
-
config: z.record(z.unknown()).optional(),
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
export const AuthSchema = z.object({
|
|
57
|
-
enabled: z.boolean().default(false),
|
|
58
|
-
apiKeys: z.array(z.string()).default([]),
|
|
59
|
-
sessionIsolation: z.boolean().default(true),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export const ChannelSchema = z.object({
|
|
63
|
-
type: z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook']),
|
|
64
|
-
port: z.number().optional(),
|
|
65
|
-
config: z.record(z.unknown()).optional(),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
export const LongTermMemorySchema = z.object({
|
|
69
|
-
provider: z.enum(['in-memory', 'deepbrain']).default('in-memory'),
|
|
70
|
-
collection: z.string().optional(),
|
|
71
|
-
config: z.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
export const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
export const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// ─── OAD Schema v1 ───────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
export const SkillRefSchema = z.object({
|
|
6
|
+
name: z.string(),
|
|
7
|
+
description: z.string().optional(),
|
|
8
|
+
config: z.record(z.unknown()).optional(),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const WorkflowStepSchema: z.ZodType<any> = z.lazy(() => z.object({
|
|
12
|
+
id: z.string(),
|
|
13
|
+
type: z.enum(['skill', 'tool', 'agent', 'condition', 'parallel']),
|
|
14
|
+
name: z.string(),
|
|
15
|
+
config: z.record(z.unknown()).optional(),
|
|
16
|
+
condition: z.string().optional(),
|
|
17
|
+
branches: z.object({ if: z.array(WorkflowStepSchema), else: z.array(WorkflowStepSchema).optional() }).optional(),
|
|
18
|
+
parallel: z.array(WorkflowStepSchema).optional(),
|
|
19
|
+
timeout: z.number().optional(),
|
|
20
|
+
retries: z.number().optional(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
export const WorkflowSchema = z.object({
|
|
24
|
+
name: z.string(),
|
|
25
|
+
description: z.string().optional(),
|
|
26
|
+
version: z.string().optional(),
|
|
27
|
+
steps: z.array(WorkflowStepSchema).default([]),
|
|
28
|
+
onError: z.enum(['stop', 'skip', 'retry']).optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const VoiceSchema = z.object({
|
|
32
|
+
enabled: z.boolean().default(false),
|
|
33
|
+
sttProvider: z.string().optional(),
|
|
34
|
+
ttsProvider: z.string().optional(),
|
|
35
|
+
language: z.string().optional(),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const WebhookSchema = z.object({
|
|
39
|
+
path: z.string().optional(),
|
|
40
|
+
secret: z.string().optional(),
|
|
41
|
+
retryAttempts: z.number().optional(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const HITLSchema = z.object({
|
|
45
|
+
enabled: z.boolean().default(false),
|
|
46
|
+
requireApproval: z.array(z.string()).default([]),
|
|
47
|
+
defaultTimeoutMs: z.number().default(60000),
|
|
48
|
+
defaultAction: z.enum(['approve', 'deny']).default('deny'),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const PluginRefSchema = z.object({
|
|
52
|
+
name: z.string(),
|
|
53
|
+
config: z.record(z.unknown()).optional(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const AuthSchema = z.object({
|
|
57
|
+
enabled: z.boolean().default(false),
|
|
58
|
+
apiKeys: z.array(z.string()).default([]),
|
|
59
|
+
sessionIsolation: z.boolean().default(true),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const ChannelSchema = z.object({
|
|
63
|
+
type: z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook', 'wechat', 'feishu', 'email', 'slack', 'discord']),
|
|
64
|
+
port: z.number().optional(),
|
|
65
|
+
config: z.record(z.unknown()).optional(),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const LongTermMemorySchema = z.object({
|
|
69
|
+
provider: z.enum(['in-memory', 'deepbrain']).default('in-memory'),
|
|
70
|
+
collection: z.string().optional(),
|
|
71
|
+
config: z.object({
|
|
72
|
+
database: z.string().optional(),
|
|
73
|
+
embeddingProvider: z.string().optional(),
|
|
74
|
+
autoLearn: z.boolean().optional(),
|
|
75
|
+
autoRecall: z.boolean().optional(),
|
|
76
|
+
evolveInterval: z.number().optional(),
|
|
77
|
+
}).passthrough().optional(),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
export const MemorySchema = z.object({
|
|
81
|
+
shortTerm: z.boolean().default(true),
|
|
82
|
+
longTerm: z.union([z.boolean(), LongTermMemorySchema]).default(false),
|
|
83
|
+
provider: z.string().optional(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const TrustLevel = z.enum(['sandbox', 'verified', 'certified', 'listed']);
|
|
87
|
+
|
|
88
|
+
export const DTVSchema = z.object({
|
|
89
|
+
trust: z.object({
|
|
90
|
+
level: TrustLevel.default('sandbox'),
|
|
91
|
+
}).optional(),
|
|
92
|
+
value: z.object({
|
|
93
|
+
metrics: z.array(z.string()).default([]),
|
|
94
|
+
}).optional(),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const ProviderSchema = z.object({
|
|
98
|
+
default: z.string().default('deepseek'),
|
|
99
|
+
allowed: z.array(z.string()).default(['openai', 'deepseek', 'qwen']),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
export const MarketplaceSchema = z.object({
|
|
103
|
+
certified: z.boolean().default(false),
|
|
104
|
+
category: z.string().optional(),
|
|
105
|
+
pricing: z.enum(['free', 'freemium', 'paid', 'enterprise']).optional(),
|
|
106
|
+
tags: z.array(z.string()).optional(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export const MetadataSchema = z.object({
|
|
110
|
+
name: z.string(),
|
|
111
|
+
version: z.string().default('1.0.0'),
|
|
112
|
+
description: z.string().optional(),
|
|
113
|
+
author: z.string().optional(),
|
|
114
|
+
license: z.string().default('Apache-2.0'),
|
|
115
|
+
marketplace: MarketplaceSchema.optional(),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
export const RoomSchema = z.object({
|
|
119
|
+
name: z.string(),
|
|
120
|
+
agents: z.array(z.string()).default([]),
|
|
121
|
+
topics: z.array(z.string()).default([]),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
export const StreamingSchema = z.object({
|
|
125
|
+
enabled: z.boolean().default(false),
|
|
126
|
+
chunkSize: z.number().optional(),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const MCPServerSchema = z.object({
|
|
130
|
+
name: z.string(),
|
|
131
|
+
command: z.string(),
|
|
132
|
+
args: z.array(z.string()).optional(),
|
|
133
|
+
env: z.record(z.string()).optional(),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export const MCPServeSchema = z.object({
|
|
137
|
+
enabled: z.boolean().default(false),
|
|
138
|
+
mode: z.enum(['stdio', 'http']).default('stdio'),
|
|
139
|
+
port: z.number().default(3002),
|
|
140
|
+
exposedTools: z.array(z.string()).optional(),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export const ToolsSchema = z.object({
|
|
144
|
+
builtin: z.array(z.string()).optional(),
|
|
145
|
+
mcp: z.array(MCPServerSchema).optional(),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
export const TelemetrySchema = z.object({
|
|
149
|
+
enabled: z.boolean().default(false),
|
|
150
|
+
exporter: z.enum(['console', 'file', 'otlp']).default('console'),
|
|
151
|
+
endpoint: z.string().optional(),
|
|
152
|
+
filePath: z.string().optional(),
|
|
153
|
+
maxSpans: z.number().optional(),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
export const AGUIProtocolSchema = z.object({
|
|
157
|
+
enabled: z.boolean().default(false),
|
|
158
|
+
path: z.string().default('/agui'),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
export const ProtocolsSchema = z.object({
|
|
162
|
+
a2a: z.object({
|
|
163
|
+
enabled: z.boolean().default(false),
|
|
164
|
+
port: z.number().optional(),
|
|
165
|
+
}).optional(),
|
|
166
|
+
agui: AGUIProtocolSchema.optional(),
|
|
167
|
+
mcp: MCPServeSchema.optional(),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
export const SpecSchema = z.object({
|
|
171
|
+
provider: ProviderSchema.optional(),
|
|
172
|
+
model: z.string().default('deepseek-chat'),
|
|
173
|
+
systemPrompt: z.string().optional(),
|
|
174
|
+
skills: z.array(SkillRefSchema).default([]),
|
|
175
|
+
channels: z.array(ChannelSchema).default([]),
|
|
176
|
+
memory: MemorySchema.optional(),
|
|
177
|
+
tools: ToolsSchema.optional(),
|
|
178
|
+
dtv: DTVSchema.optional(),
|
|
179
|
+
room: RoomSchema.optional(),
|
|
180
|
+
streaming: z.union([z.boolean(), StreamingSchema]).default(false),
|
|
181
|
+
locale: z.enum(['en', 'zh-CN']).optional(),
|
|
182
|
+
workflows: z.array(WorkflowSchema).optional(),
|
|
183
|
+
voice: VoiceSchema.optional(),
|
|
184
|
+
webhook: WebhookSchema.optional(),
|
|
185
|
+
hitl: HITLSchema.optional(),
|
|
186
|
+
auth: AuthSchema.optional(),
|
|
187
|
+
telemetry: TelemetrySchema.optional(),
|
|
188
|
+
protocols: ProtocolsSchema.optional(),
|
|
189
|
+
plugins: z.array(PluginRefSchema).optional(),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
export const OADSchema = z.object({
|
|
193
|
+
apiVersion: z.literal('opc/v1'),
|
|
194
|
+
kind: z.literal('Agent'),
|
|
195
|
+
metadata: MetadataSchema,
|
|
196
|
+
spec: SpecSchema,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
export type OADDocument = z.infer<typeof OADSchema>;
|
|
200
|
+
export type SkillRef = z.infer<typeof SkillRefSchema>;
|
|
201
|
+
export type Channel = z.infer<typeof ChannelSchema>;
|
|
202
|
+
export type Metadata = z.infer<typeof MetadataSchema>;
|
|
203
|
+
export type Spec = z.infer<typeof SpecSchema>;
|
|
204
|
+
export type TrustLevelType = string;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
|
|
3
|
+
export type ApprovalPolicy = 'always' | 'dangerous' | 'never';
|
|
4
|
+
|
|
5
|
+
export interface ApprovalRequest {
|
|
6
|
+
id: string;
|
|
7
|
+
type: 'shell' | 'file_write' | 'file_delete' | 'network' | 'plugin';
|
|
8
|
+
command: string;
|
|
9
|
+
description: string;
|
|
10
|
+
requestedAt: Date;
|
|
11
|
+
status: 'pending' | 'approved' | 'denied';
|
|
12
|
+
approvedBy?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ApprovalManager {
|
|
16
|
+
private policy: ApprovalPolicy;
|
|
17
|
+
private pendingApprovals: Map<string, ApprovalRequest> = new Map();
|
|
18
|
+
private allowlist: Set<string> = new Set();
|
|
19
|
+
private blocklist: Set<string> = new Set();
|
|
20
|
+
|
|
21
|
+
private static readonly DANGEROUS_PATTERNS = [
|
|
22
|
+
/rm\s+-rf/i, /del\s+\/s/i, /format\s+/i,
|
|
23
|
+
/DROP\s+TABLE/i, /DELETE\s+FROM/i,
|
|
24
|
+
/curl.*\|.*sh/i, /wget.*\|.*sh/i,
|
|
25
|
+
/chmod\s+777/i, /sudo\s+/i,
|
|
26
|
+
/npm\s+publish/i,
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
constructor(policy: ApprovalPolicy = 'dangerous') {
|
|
30
|
+
this.policy = policy;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getPolicy(): ApprovalPolicy {
|
|
34
|
+
return this.policy;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setPolicy(policy: ApprovalPolicy): void {
|
|
38
|
+
this.policy = policy;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
needsApproval(type: string, command: string): boolean {
|
|
42
|
+
// Blocklist always needs approval (effectively blocked)
|
|
43
|
+
if (this.isBlocked(command)) return true;
|
|
44
|
+
// Allowlist never needs approval
|
|
45
|
+
if (this.isAllowed(command)) return false;
|
|
46
|
+
|
|
47
|
+
if (this.policy === 'never') return false;
|
|
48
|
+
if (this.policy === 'always') return true;
|
|
49
|
+
// 'dangerous'
|
|
50
|
+
return this.isDangerous(type, command);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private isDangerous(_type: string, command: string): boolean {
|
|
54
|
+
return ApprovalManager.DANGEROUS_PATTERNS.some(p => p.test(command));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private isAllowed(command: string): boolean {
|
|
58
|
+
for (const pattern of this.allowlist) {
|
|
59
|
+
if (command.includes(pattern)) return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private isBlocked(command: string): boolean {
|
|
65
|
+
for (const pattern of this.blocklist) {
|
|
66
|
+
if (command.includes(pattern)) return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
requestApproval(type: ApprovalRequest['type'], command: string, description: string): ApprovalRequest {
|
|
72
|
+
const request: ApprovalRequest = {
|
|
73
|
+
id: randomUUID(),
|
|
74
|
+
type,
|
|
75
|
+
command,
|
|
76
|
+
description,
|
|
77
|
+
requestedAt: new Date(),
|
|
78
|
+
status: 'pending',
|
|
79
|
+
};
|
|
80
|
+
this.pendingApprovals.set(request.id, request);
|
|
81
|
+
return request;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
approve(id: string, approver: string): void {
|
|
85
|
+
const req = this.pendingApprovals.get(id);
|
|
86
|
+
if (!req) throw new Error(`Approval request ${id} not found`);
|
|
87
|
+
if (req.status !== 'pending') throw new Error(`Request ${id} is already ${req.status}`);
|
|
88
|
+
req.status = 'approved';
|
|
89
|
+
req.approvedBy = approver;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
deny(id: string, approver: string): void {
|
|
93
|
+
const req = this.pendingApprovals.get(id);
|
|
94
|
+
if (!req) throw new Error(`Approval request ${id} not found`);
|
|
95
|
+
if (req.status !== 'pending') throw new Error(`Request ${id} is already ${req.status}`);
|
|
96
|
+
req.status = 'denied';
|
|
97
|
+
req.approvedBy = approver;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getRequest(id: string): ApprovalRequest | undefined {
|
|
101
|
+
return this.pendingApprovals.get(id);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addToAllowlist(pattern: string): void {
|
|
105
|
+
this.allowlist.add(pattern);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
removeFromAllowlist(pattern: string): void {
|
|
109
|
+
this.allowlist.delete(pattern);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
addToBlocklist(pattern: string): void {
|
|
113
|
+
this.blocklist.add(pattern);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
removeFromBlocklist(pattern: string): void {
|
|
117
|
+
this.blocklist.delete(pattern);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getPending(): ApprovalRequest[] {
|
|
121
|
+
return Array.from(this.pendingApprovals.values()).filter(r => r.status === 'pending');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getAllowlist(): string[] {
|
|
125
|
+
return Array.from(this.allowlist);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getBlocklist(): string[] {
|
|
129
|
+
return Array.from(this.blocklist);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
|
|
6
|
+
export class KeyManager {
|
|
7
|
+
private keys: Map<string, string> = new Map();
|
|
8
|
+
private keyFile: string;
|
|
9
|
+
private secret: Buffer;
|
|
10
|
+
|
|
11
|
+
constructor(keyFile: string = '.opc/keys.json') {
|
|
12
|
+
this.keyFile = path.resolve(keyFile);
|
|
13
|
+
this.secret = this.deriveSecret();
|
|
14
|
+
this.load();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private deriveSecret(): Buffer {
|
|
18
|
+
// Derive a key from machine-specific info (hostname + homedir)
|
|
19
|
+
const machineId = `${os.hostname()}:${os.homedir()}:opc-agent-keys`;
|
|
20
|
+
return crypto.createHash('sha256').update(machineId).digest();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
set(name: string, value: string): void {
|
|
24
|
+
this.keys.set(name, value);
|
|
25
|
+
this.save();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get(name: string): string | undefined {
|
|
29
|
+
return this.keys.get(name);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
delete(name: string): boolean {
|
|
33
|
+
const result = this.keys.delete(name);
|
|
34
|
+
if (result) this.save();
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
list(): string[] {
|
|
39
|
+
return Array.from(this.keys.keys());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private load(): void {
|
|
43
|
+
try {
|
|
44
|
+
if (fs.existsSync(this.keyFile)) {
|
|
45
|
+
const data = JSON.parse(fs.readFileSync(this.keyFile, 'utf-8'));
|
|
46
|
+
for (const [name, encoded] of Object.entries(data)) {
|
|
47
|
+
try {
|
|
48
|
+
this.keys.set(name, this.decode(encoded as string));
|
|
49
|
+
} catch {
|
|
50
|
+
// Skip corrupted entries
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
// File doesn't exist or is corrupted — start fresh
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private save(): void {
|
|
60
|
+
const dir = path.dirname(this.keyFile);
|
|
61
|
+
if (!fs.existsSync(dir)) {
|
|
62
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
const data: Record<string, string> = {};
|
|
65
|
+
for (const [name, value] of this.keys) {
|
|
66
|
+
data[name] = this.encode(value);
|
|
67
|
+
}
|
|
68
|
+
fs.writeFileSync(this.keyFile, JSON.stringify(data, null, 2), 'utf-8');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private encode(value: string): string {
|
|
72
|
+
const iv = crypto.randomBytes(16);
|
|
73
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', this.secret, iv);
|
|
74
|
+
let encrypted = cipher.update(value, 'utf-8', 'hex');
|
|
75
|
+
encrypted += cipher.final('hex');
|
|
76
|
+
return iv.toString('hex') + ':' + encrypted;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private decode(encoded: string): string {
|
|
80
|
+
const [ivHex, encrypted] = encoded.split(':');
|
|
81
|
+
const iv = Buffer.from(ivHex, 'hex');
|
|
82
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', this.secret, iv);
|
|
83
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf-8');
|
|
84
|
+
decrypted += decipher.final('utf-8');
|
|
85
|
+
return decrypted;
|
|
86
|
+
}
|
|
87
|
+
}
|