opc-agent 1.2.1 → 1.3.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.
Files changed (152) hide show
  1. package/CONTRIBUTING.md +75 -75
  2. package/README.md +235 -358
  3. package/README.zh-CN.md +415 -415
  4. package/dist/channels/web.js +256 -256
  5. package/dist/core/knowledge.d.ts +5 -0
  6. package/dist/core/knowledge.js +39 -2
  7. package/dist/deploy/hermes.js +22 -22
  8. package/dist/deploy/openclaw.js +31 -31
  9. package/dist/index.d.ts +0 -4
  10. package/dist/index.js +1 -7
  11. package/dist/providers/index.d.ts +1 -1
  12. package/dist/providers/index.js +158 -14
  13. package/dist/schema/oad.d.ts +3 -3
  14. package/dist/templates/code-reviewer.js +5 -5
  15. package/dist/templates/customer-service.js +2 -2
  16. package/dist/templates/data-analyst.js +5 -5
  17. package/dist/templates/knowledge-base.js +2 -2
  18. package/dist/templates/sales-assistant.js +4 -4
  19. package/dist/templates/teacher.js +6 -6
  20. package/docs/.vitepress/config.ts +103 -103
  21. package/docs/api/cli.md +48 -48
  22. package/docs/api/oad-schema.md +64 -64
  23. package/docs/api/sdk.md +80 -80
  24. package/docs/guide/concepts.md +51 -51
  25. package/docs/guide/configuration.md +79 -79
  26. package/docs/guide/deployment.md +42 -42
  27. package/docs/guide/getting-started.md +44 -44
  28. package/docs/guide/templates.md +28 -28
  29. package/docs/guide/testing.md +84 -84
  30. package/docs/index.md +27 -27
  31. package/docs/zh/api/cli.md +54 -54
  32. package/docs/zh/api/oad-schema.md +87 -87
  33. package/docs/zh/api/sdk.md +102 -102
  34. package/docs/zh/guide/concepts.md +104 -104
  35. package/docs/zh/guide/configuration.md +135 -135
  36. package/docs/zh/guide/deployment.md +81 -81
  37. package/docs/zh/guide/getting-started.md +82 -82
  38. package/docs/zh/guide/templates.md +84 -84
  39. package/docs/zh/guide/testing.md +88 -88
  40. package/docs/zh/index.md +27 -27
  41. package/examples/customer-service-demo/README.md +90 -90
  42. package/examples/customer-service-demo/oad.yaml +107 -107
  43. package/package.json +50 -50
  44. package/src/analytics/index.ts +66 -66
  45. package/src/channels/discord.ts +192 -192
  46. package/src/channels/email.ts +177 -177
  47. package/src/channels/feishu.ts +236 -236
  48. package/src/channels/index.ts +15 -15
  49. package/src/channels/slack.ts +160 -160
  50. package/src/channels/telegram.ts +90 -90
  51. package/src/channels/voice.ts +106 -106
  52. package/src/channels/webhook.ts +199 -199
  53. package/src/channels/websocket.ts +87 -87
  54. package/src/channels/wechat.ts +149 -149
  55. package/src/cli.ts +119 -1
  56. package/src/core/a2a.ts +143 -143
  57. package/src/core/agent.ts +152 -152
  58. package/src/core/analytics-engine.ts +186 -186
  59. package/src/core/auth.ts +57 -57
  60. package/src/core/cache.ts +141 -141
  61. package/src/core/compose.ts +77 -77
  62. package/src/core/config.ts +14 -14
  63. package/src/core/errors.ts +148 -148
  64. package/src/core/hitl.ts +138 -138
  65. package/src/core/logger.ts +57 -57
  66. package/src/core/orchestrator.ts +215 -215
  67. package/src/core/performance.ts +187 -187
  68. package/src/core/rate-limiter.ts +128 -128
  69. package/src/core/room.ts +109 -109
  70. package/src/core/runtime.ts +152 -152
  71. package/src/core/sandbox.ts +101 -101
  72. package/src/core/security.ts +171 -171
  73. package/src/core/types.ts +68 -68
  74. package/src/core/versioning.ts +106 -106
  75. package/src/core/watch.ts +178 -178
  76. package/src/core/workflow.ts +235 -235
  77. package/src/deploy/hermes.ts +156 -156
  78. package/src/deploy/openclaw.ts +200 -200
  79. package/src/i18n/index.ts +216 -216
  80. package/src/index.ts +6 -2
  81. package/src/memory/deepbrain.ts +108 -108
  82. package/src/memory/index.ts +34 -34
  83. package/src/plugins/index.ts +208 -208
  84. package/src/schema/oad.ts +154 -155
  85. package/src/skills/base.ts +16 -16
  86. package/src/skills/document.ts +100 -100
  87. package/src/skills/http.ts +35 -35
  88. package/src/skills/index.ts +27 -27
  89. package/src/skills/scheduler.ts +80 -80
  90. package/src/skills/webhook-trigger.ts +59 -59
  91. package/src/templates/code-reviewer.ts +30 -34
  92. package/src/templates/customer-service.ts +76 -80
  93. package/src/templates/data-analyst.ts +66 -70
  94. package/src/templates/executive-assistant.ts +71 -71
  95. package/src/templates/financial-advisor.ts +60 -60
  96. package/src/templates/knowledge-base.ts +27 -31
  97. package/src/templates/legal-assistant.ts +71 -71
  98. package/src/templates/sales-assistant.ts +75 -79
  99. package/src/templates/teacher.ts +75 -79
  100. package/src/testing/index.ts +181 -181
  101. package/src/tools/calculator.ts +73 -73
  102. package/src/tools/datetime.ts +149 -149
  103. package/src/tools/json-transform.ts +187 -187
  104. package/src/tools/mcp.ts +76 -76
  105. package/src/tools/text-analysis.ts +116 -116
  106. package/src/traces/index.ts +132 -0
  107. package/templates/Dockerfile +15 -15
  108. package/templates/code-reviewer/README.md +27 -27
  109. package/templates/code-reviewer/oad.yaml +41 -41
  110. package/templates/customer-service/README.md +22 -22
  111. package/templates/customer-service/oad.yaml +36 -36
  112. package/templates/docker-compose.yml +21 -21
  113. package/templates/ecommerce-assistant/README.md +45 -45
  114. package/templates/ecommerce-assistant/oad.yaml +47 -47
  115. package/templates/knowledge-base/README.md +28 -28
  116. package/templates/knowledge-base/oad.yaml +38 -38
  117. package/templates/sales-assistant/README.md +26 -26
  118. package/templates/sales-assistant/oad.yaml +43 -43
  119. package/templates/tech-support/README.md +43 -43
  120. package/templates/tech-support/oad.yaml +45 -45
  121. package/tests/a2a.test.ts +66 -66
  122. package/tests/agent.test.ts +72 -72
  123. package/tests/analytics.test.ts +50 -50
  124. package/tests/channel.test.ts +39 -39
  125. package/tests/e2e.test.ts +134 -134
  126. package/tests/errors.test.ts +83 -83
  127. package/tests/hitl.test.ts +71 -71
  128. package/tests/i18n.test.ts +41 -41
  129. package/tests/mcp.test.ts +54 -54
  130. package/tests/oad.test.ts +68 -68
  131. package/tests/performance.test.ts +115 -115
  132. package/tests/plugin.test.ts +74 -74
  133. package/tests/room.test.ts +106 -106
  134. package/tests/runtime.test.ts +42 -42
  135. package/tests/sandbox.test.ts +46 -46
  136. package/tests/security.test.ts +60 -60
  137. package/tests/templates.test.ts +77 -77
  138. package/tests/v070.test.ts +76 -76
  139. package/tests/versioning.test.ts +75 -75
  140. package/tests/voice.test.ts +61 -61
  141. package/tests/webhook.test.ts +29 -29
  142. package/tests/workflow.test.ts +143 -143
  143. package/tsconfig.json +19 -19
  144. package/vitest.config.ts +9 -9
  145. package/dist/core/streaming.d.ts +0 -56
  146. package/dist/core/streaming.js +0 -160
  147. package/dist/tools/gateway.d.ts +0 -28
  148. package/dist/tools/gateway.js +0 -177
  149. package/src/dtv/data.ts +0 -29
  150. package/src/dtv/trust.ts +0 -43
  151. package/src/dtv/value.ts +0 -47
  152. package/src/marketplace/index.ts +0 -223
@@ -1,235 +1,235 @@
1
- import { EventEmitter } from 'events';
2
- import type { Message, AgentContext, ISkill, IAgent } from './types';
3
- import { Logger } from './logger';
4
-
5
- // ── Workflow Types ──────────────────────────────────────────
6
-
7
- export type StepType = 'skill' | 'tool' | 'agent' | 'condition' | 'parallel';
8
-
9
- export interface WorkflowStep {
10
- id: string;
11
- type: StepType;
12
- name: string;
13
- config?: Record<string, unknown>;
14
- /** For condition steps */
15
- condition?: string;
16
- branches?: { if: WorkflowStep[]; else?: WorkflowStep[] };
17
- /** For parallel steps */
18
- parallel?: WorkflowStep[];
19
- /** Timeout in ms */
20
- timeout?: number;
21
- /** Retry count */
22
- retries?: number;
23
- }
24
-
25
- export interface WorkflowDefinition {
26
- name: string;
27
- description?: string;
28
- version?: string;
29
- steps: WorkflowStep[];
30
- onError?: 'stop' | 'skip' | 'retry';
31
- }
32
-
33
- export interface StepResult {
34
- stepId: string;
35
- status: 'success' | 'skipped' | 'error';
36
- output?: string;
37
- error?: string;
38
- durationMs: number;
39
- }
40
-
41
- export interface WorkflowResult {
42
- workflow: string;
43
- status: 'completed' | 'failed' | 'partial';
44
- steps: StepResult[];
45
- totalDurationMs: number;
46
- }
47
-
48
- // ── Workflow Engine ─────────────────────────────────────────
49
-
50
- export class WorkflowEngine extends EventEmitter {
51
- private workflows: Map<string, WorkflowDefinition> = new Map();
52
- private skills: Map<string, ISkill> = new Map();
53
- private agents: Map<string, IAgent> = new Map();
54
- private logger = new Logger('workflow');
55
-
56
- registerWorkflow(workflow: WorkflowDefinition): void {
57
- this.workflows.set(workflow.name, workflow);
58
- this.logger.info('Workflow registered', { name: workflow.name, steps: workflow.steps.length });
59
- }
60
-
61
- unregisterWorkflow(name: string): void {
62
- this.workflows.delete(name);
63
- }
64
-
65
- getWorkflow(name: string): WorkflowDefinition | undefined {
66
- return this.workflows.get(name);
67
- }
68
-
69
- listWorkflows(): WorkflowDefinition[] {
70
- return Array.from(this.workflows.values());
71
- }
72
-
73
- registerSkill(skill: ISkill): void {
74
- this.skills.set(skill.name, skill);
75
- }
76
-
77
- registerAgent(agent: IAgent): void {
78
- this.agents.set(agent.name, agent);
79
- }
80
-
81
- async run(name: string, context: AgentContext, input?: string): Promise<WorkflowResult> {
82
- const workflow = this.workflows.get(name);
83
- if (!workflow) throw new Error(`Workflow "${name}" not found`);
84
-
85
- const startTime = Date.now();
86
- const results: StepResult[] = [];
87
- let failed = false;
88
-
89
- this.emit('workflow:start', { name, input });
90
-
91
- try {
92
- await this.executeSteps(workflow.steps, context, input ?? '', results, workflow.onError ?? 'stop');
93
- } catch (err) {
94
- failed = true;
95
- this.logger.error('Workflow failed', { name, error: (err as Error).message });
96
- }
97
-
98
- const result: WorkflowResult = {
99
- workflow: name,
100
- status: failed ? 'failed' : results.some(r => r.status === 'error') ? 'partial' : 'completed',
101
- steps: results,
102
- totalDurationMs: Date.now() - startTime,
103
- };
104
-
105
- this.emit('workflow:end', result);
106
- return result;
107
- }
108
-
109
- private async executeSteps(
110
- steps: WorkflowStep[],
111
- context: AgentContext,
112
- input: string,
113
- results: StepResult[],
114
- onError: string,
115
- ): Promise<string> {
116
- let currentInput = input;
117
-
118
- for (const step of steps) {
119
- const stepStart = Date.now();
120
-
121
- try {
122
- if (step.type === 'parallel' && step.parallel) {
123
- const parallelResults = await Promise.all(
124
- step.parallel.map(s => this.executeSingleStep(s, context, currentInput)),
125
- );
126
- const combined = parallelResults.map(r => r.output ?? '').join('\n');
127
- for (const r of parallelResults) results.push(r);
128
- currentInput = combined;
129
- } else if (step.type === 'condition' && step.branches) {
130
- const conditionMet = this.evaluateCondition(step.condition ?? '', currentInput, context);
131
- const branch = conditionMet ? step.branches.if : (step.branches.else ?? []);
132
- results.push({
133
- stepId: step.id,
134
- status: 'success',
135
- output: `condition=${conditionMet}`,
136
- durationMs: Date.now() - stepStart,
137
- });
138
- currentInput = await this.executeSteps(branch, context, currentInput, results, onError);
139
- } else {
140
- const result = await this.executeSingleStep(step, context, currentInput);
141
- results.push(result);
142
- if (result.status === 'success' && result.output) {
143
- currentInput = result.output;
144
- }
145
- if (result.status === 'error' && onError === 'stop') {
146
- throw new Error(`Step "${step.id}" failed: ${result.error}`);
147
- }
148
- }
149
- } catch (err) {
150
- if (onError === 'stop') throw err;
151
- // skip: continue
152
- }
153
- }
154
-
155
- return currentInput;
156
- }
157
-
158
- private async executeSingleStep(
159
- step: WorkflowStep,
160
- context: AgentContext,
161
- input: string,
162
- ): Promise<StepResult> {
163
- const startTime = Date.now();
164
- let retries = step.retries ?? 0;
165
-
166
- while (true) {
167
- try {
168
- const output = await this.executeStepAction(step, context, input);
169
- return {
170
- stepId: step.id,
171
- status: 'success',
172
- output,
173
- durationMs: Date.now() - startTime,
174
- };
175
- } catch (err) {
176
- if (retries > 0) {
177
- retries--;
178
- continue;
179
- }
180
- return {
181
- stepId: step.id,
182
- status: 'error',
183
- error: (err as Error).message,
184
- durationMs: Date.now() - startTime,
185
- };
186
- }
187
- }
188
- }
189
-
190
- private async executeStepAction(step: WorkflowStep, context: AgentContext, input: string): Promise<string> {
191
- const message: Message = {
192
- id: `wf_${step.id}_${Date.now()}`,
193
- role: 'user',
194
- content: input,
195
- timestamp: Date.now(),
196
- metadata: { workflowStep: step.id },
197
- };
198
-
199
- switch (step.type) {
200
- case 'skill': {
201
- const skill = this.skills.get(step.name);
202
- if (!skill) throw new Error(`Skill "${step.name}" not found`);
203
- const result = await skill.execute(context, message);
204
- return result.response ?? '';
205
- }
206
- case 'agent': {
207
- const agent = this.agents.get(step.name);
208
- if (!agent) throw new Error(`Agent "${step.name}" not found`);
209
- const response = await agent.handleMessage(message);
210
- return response.content;
211
- }
212
- case 'tool': {
213
- // Tools are executed via config callback
214
- const toolFn = step.config?.handler as ((input: string) => Promise<string>) | undefined;
215
- if (toolFn) return await toolFn(input);
216
- return `[tool:${step.name}] executed`;
217
- }
218
- default:
219
- return input;
220
- }
221
- }
222
-
223
- private evaluateCondition(condition: string, input: string, _context: AgentContext): boolean {
224
- // Simple condition evaluator: supports "contains:keyword", "length>N", "true", "false"
225
- if (condition === 'true') return true;
226
- if (condition === 'false') return false;
227
- if (condition.startsWith('contains:')) {
228
- return input.toLowerCase().includes(condition.slice(9).toLowerCase());
229
- }
230
- if (condition.startsWith('length>')) {
231
- return input.length > parseInt(condition.slice(7), 10);
232
- }
233
- return !!condition;
234
- }
235
- }
1
+ import { EventEmitter } from 'events';
2
+ import type { Message, AgentContext, ISkill, IAgent } from './types';
3
+ import { Logger } from './logger';
4
+
5
+ // ── Workflow Types ──────────────────────────────────────────
6
+
7
+ export type StepType = 'skill' | 'tool' | 'agent' | 'condition' | 'parallel';
8
+
9
+ export interface WorkflowStep {
10
+ id: string;
11
+ type: StepType;
12
+ name: string;
13
+ config?: Record<string, unknown>;
14
+ /** For condition steps */
15
+ condition?: string;
16
+ branches?: { if: WorkflowStep[]; else?: WorkflowStep[] };
17
+ /** For parallel steps */
18
+ parallel?: WorkflowStep[];
19
+ /** Timeout in ms */
20
+ timeout?: number;
21
+ /** Retry count */
22
+ retries?: number;
23
+ }
24
+
25
+ export interface WorkflowDefinition {
26
+ name: string;
27
+ description?: string;
28
+ version?: string;
29
+ steps: WorkflowStep[];
30
+ onError?: 'stop' | 'skip' | 'retry';
31
+ }
32
+
33
+ export interface StepResult {
34
+ stepId: string;
35
+ status: 'success' | 'skipped' | 'error';
36
+ output?: string;
37
+ error?: string;
38
+ durationMs: number;
39
+ }
40
+
41
+ export interface WorkflowResult {
42
+ workflow: string;
43
+ status: 'completed' | 'failed' | 'partial';
44
+ steps: StepResult[];
45
+ totalDurationMs: number;
46
+ }
47
+
48
+ // ── Workflow Engine ─────────────────────────────────────────
49
+
50
+ export class WorkflowEngine extends EventEmitter {
51
+ private workflows: Map<string, WorkflowDefinition> = new Map();
52
+ private skills: Map<string, ISkill> = new Map();
53
+ private agents: Map<string, IAgent> = new Map();
54
+ private logger = new Logger('workflow');
55
+
56
+ registerWorkflow(workflow: WorkflowDefinition): void {
57
+ this.workflows.set(workflow.name, workflow);
58
+ this.logger.info('Workflow registered', { name: workflow.name, steps: workflow.steps.length });
59
+ }
60
+
61
+ unregisterWorkflow(name: string): void {
62
+ this.workflows.delete(name);
63
+ }
64
+
65
+ getWorkflow(name: string): WorkflowDefinition | undefined {
66
+ return this.workflows.get(name);
67
+ }
68
+
69
+ listWorkflows(): WorkflowDefinition[] {
70
+ return Array.from(this.workflows.values());
71
+ }
72
+
73
+ registerSkill(skill: ISkill): void {
74
+ this.skills.set(skill.name, skill);
75
+ }
76
+
77
+ registerAgent(agent: IAgent): void {
78
+ this.agents.set(agent.name, agent);
79
+ }
80
+
81
+ async run(name: string, context: AgentContext, input?: string): Promise<WorkflowResult> {
82
+ const workflow = this.workflows.get(name);
83
+ if (!workflow) throw new Error(`Workflow "${name}" not found`);
84
+
85
+ const startTime = Date.now();
86
+ const results: StepResult[] = [];
87
+ let failed = false;
88
+
89
+ this.emit('workflow:start', { name, input });
90
+
91
+ try {
92
+ await this.executeSteps(workflow.steps, context, input ?? '', results, workflow.onError ?? 'stop');
93
+ } catch (err) {
94
+ failed = true;
95
+ this.logger.error('Workflow failed', { name, error: (err as Error).message });
96
+ }
97
+
98
+ const result: WorkflowResult = {
99
+ workflow: name,
100
+ status: failed ? 'failed' : results.some(r => r.status === 'error') ? 'partial' : 'completed',
101
+ steps: results,
102
+ totalDurationMs: Date.now() - startTime,
103
+ };
104
+
105
+ this.emit('workflow:end', result);
106
+ return result;
107
+ }
108
+
109
+ private async executeSteps(
110
+ steps: WorkflowStep[],
111
+ context: AgentContext,
112
+ input: string,
113
+ results: StepResult[],
114
+ onError: string,
115
+ ): Promise<string> {
116
+ let currentInput = input;
117
+
118
+ for (const step of steps) {
119
+ const stepStart = Date.now();
120
+
121
+ try {
122
+ if (step.type === 'parallel' && step.parallel) {
123
+ const parallelResults = await Promise.all(
124
+ step.parallel.map(s => this.executeSingleStep(s, context, currentInput)),
125
+ );
126
+ const combined = parallelResults.map(r => r.output ?? '').join('\n');
127
+ for (const r of parallelResults) results.push(r);
128
+ currentInput = combined;
129
+ } else if (step.type === 'condition' && step.branches) {
130
+ const conditionMet = this.evaluateCondition(step.condition ?? '', currentInput, context);
131
+ const branch = conditionMet ? step.branches.if : (step.branches.else ?? []);
132
+ results.push({
133
+ stepId: step.id,
134
+ status: 'success',
135
+ output: `condition=${conditionMet}`,
136
+ durationMs: Date.now() - stepStart,
137
+ });
138
+ currentInput = await this.executeSteps(branch, context, currentInput, results, onError);
139
+ } else {
140
+ const result = await this.executeSingleStep(step, context, currentInput);
141
+ results.push(result);
142
+ if (result.status === 'success' && result.output) {
143
+ currentInput = result.output;
144
+ }
145
+ if (result.status === 'error' && onError === 'stop') {
146
+ throw new Error(`Step "${step.id}" failed: ${result.error}`);
147
+ }
148
+ }
149
+ } catch (err) {
150
+ if (onError === 'stop') throw err;
151
+ // skip: continue
152
+ }
153
+ }
154
+
155
+ return currentInput;
156
+ }
157
+
158
+ private async executeSingleStep(
159
+ step: WorkflowStep,
160
+ context: AgentContext,
161
+ input: string,
162
+ ): Promise<StepResult> {
163
+ const startTime = Date.now();
164
+ let retries = step.retries ?? 0;
165
+
166
+ while (true) {
167
+ try {
168
+ const output = await this.executeStepAction(step, context, input);
169
+ return {
170
+ stepId: step.id,
171
+ status: 'success',
172
+ output,
173
+ durationMs: Date.now() - startTime,
174
+ };
175
+ } catch (err) {
176
+ if (retries > 0) {
177
+ retries--;
178
+ continue;
179
+ }
180
+ return {
181
+ stepId: step.id,
182
+ status: 'error',
183
+ error: (err as Error).message,
184
+ durationMs: Date.now() - startTime,
185
+ };
186
+ }
187
+ }
188
+ }
189
+
190
+ private async executeStepAction(step: WorkflowStep, context: AgentContext, input: string): Promise<string> {
191
+ const message: Message = {
192
+ id: `wf_${step.id}_${Date.now()}`,
193
+ role: 'user',
194
+ content: input,
195
+ timestamp: Date.now(),
196
+ metadata: { workflowStep: step.id },
197
+ };
198
+
199
+ switch (step.type) {
200
+ case 'skill': {
201
+ const skill = this.skills.get(step.name);
202
+ if (!skill) throw new Error(`Skill "${step.name}" not found`);
203
+ const result = await skill.execute(context, message);
204
+ return result.response ?? '';
205
+ }
206
+ case 'agent': {
207
+ const agent = this.agents.get(step.name);
208
+ if (!agent) throw new Error(`Agent "${step.name}" not found`);
209
+ const response = await agent.handleMessage(message);
210
+ return response.content;
211
+ }
212
+ case 'tool': {
213
+ // Tools are executed via config callback
214
+ const toolFn = step.config?.handler as ((input: string) => Promise<string>) | undefined;
215
+ if (toolFn) return await toolFn(input);
216
+ return `[tool:${step.name}] executed`;
217
+ }
218
+ default:
219
+ return input;
220
+ }
221
+ }
222
+
223
+ private evaluateCondition(condition: string, input: string, _context: AgentContext): boolean {
224
+ // Simple condition evaluator: supports "contains:keyword", "length>N", "true", "false"
225
+ if (condition === 'true') return true;
226
+ if (condition === 'false') return false;
227
+ if (condition.startsWith('contains:')) {
228
+ return input.toLowerCase().includes(condition.slice(9).toLowerCase());
229
+ }
230
+ if (condition.startsWith('length>')) {
231
+ return input.length > parseInt(condition.slice(7), 10);
232
+ }
233
+ return !!condition;
234
+ }
235
+ }