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.
Files changed (160) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/CONTRIBUTING.md +75 -75
  3. package/README.md +358 -235
  4. package/README.zh-CN.md +415 -415
  5. package/dist/cli.js +34 -118
  6. package/dist/core/dashboard.d.ts +35 -0
  7. package/dist/core/dashboard.js +157 -0
  8. package/dist/core/priority.d.ts +52 -0
  9. package/dist/core/priority.js +102 -0
  10. package/dist/deploy/hermes.js +22 -22
  11. package/dist/deploy/openclaw.js +40 -31
  12. package/dist/index.d.ts +10 -3
  13. package/dist/index.js +15 -6
  14. package/dist/schema/oad.d.ts +2 -1
  15. package/dist/templates/code-reviewer.d.ts +8 -0
  16. package/dist/templates/code-reviewer.js +9 -5
  17. package/dist/templates/customer-service.d.ts +8 -0
  18. package/dist/templates/customer-service.js +6 -2
  19. package/dist/templates/data-analyst.d.ts +8 -0
  20. package/dist/templates/data-analyst.js +9 -5
  21. package/dist/templates/knowledge-base.d.ts +8 -0
  22. package/dist/templates/knowledge-base.js +6 -2
  23. package/dist/templates/sales-assistant.d.ts +8 -0
  24. package/dist/templates/sales-assistant.js +8 -4
  25. package/dist/templates/teacher.d.ts +8 -0
  26. package/dist/templates/teacher.js +10 -6
  27. package/docs/.vitepress/config.ts +103 -103
  28. package/docs/api/cli.md +48 -48
  29. package/docs/api/oad-schema.md +64 -64
  30. package/docs/api/sdk.md +80 -80
  31. package/docs/guide/concepts.md +51 -51
  32. package/docs/guide/configuration.md +79 -79
  33. package/docs/guide/deployment.md +42 -42
  34. package/docs/guide/getting-started.md +44 -44
  35. package/docs/guide/templates.md +28 -28
  36. package/docs/guide/testing.md +84 -84
  37. package/docs/index.md +27 -27
  38. package/docs/zh/api/cli.md +54 -54
  39. package/docs/zh/api/oad-schema.md +87 -87
  40. package/docs/zh/api/sdk.md +102 -102
  41. package/docs/zh/guide/concepts.md +104 -104
  42. package/docs/zh/guide/configuration.md +135 -135
  43. package/docs/zh/guide/deployment.md +81 -81
  44. package/docs/zh/guide/getting-started.md +82 -82
  45. package/docs/zh/guide/templates.md +84 -84
  46. package/docs/zh/guide/testing.md +88 -88
  47. package/docs/zh/index.md +27 -27
  48. package/examples/customer-service-demo/README.md +90 -90
  49. package/examples/customer-service-demo/oad.yaml +107 -107
  50. package/package.json +1 -1
  51. package/src/analytics/index.ts +66 -66
  52. package/src/channels/discord.ts +192 -192
  53. package/src/channels/email.ts +177 -177
  54. package/src/channels/feishu.ts +236 -236
  55. package/src/channels/index.ts +15 -15
  56. package/src/channels/slack.ts +160 -160
  57. package/src/channels/telegram.ts +90 -90
  58. package/src/channels/voice.ts +106 -106
  59. package/src/channels/webhook.ts +199 -199
  60. package/src/channels/websocket.ts +87 -87
  61. package/src/channels/wechat.ts +149 -149
  62. package/src/cli.ts +32 -124
  63. package/src/core/a2a.ts +143 -143
  64. package/src/core/agent.ts +152 -152
  65. package/src/core/analytics-engine.ts +186 -186
  66. package/src/core/auth.ts +57 -57
  67. package/src/core/cache.ts +141 -141
  68. package/src/core/compose.ts +77 -77
  69. package/src/core/config.ts +14 -14
  70. package/src/core/dashboard.ts +219 -0
  71. package/src/core/errors.ts +148 -148
  72. package/src/core/hitl.ts +138 -138
  73. package/src/core/logger.ts +57 -57
  74. package/src/core/orchestrator.ts +215 -215
  75. package/src/core/performance.ts +187 -187
  76. package/src/core/priority.ts +140 -0
  77. package/src/core/rate-limiter.ts +128 -128
  78. package/src/core/room.ts +109 -109
  79. package/src/core/runtime.ts +152 -152
  80. package/src/core/sandbox.ts +101 -101
  81. package/src/core/security.ts +171 -171
  82. package/src/core/types.ts +68 -68
  83. package/src/core/versioning.ts +106 -106
  84. package/src/core/watch.ts +178 -178
  85. package/src/core/workflow.ts +235 -235
  86. package/src/deploy/hermes.ts +156 -156
  87. package/src/deploy/openclaw.ts +200 -190
  88. package/src/dtv/data.ts +29 -0
  89. package/src/dtv/trust.ts +43 -0
  90. package/src/dtv/value.ts +47 -0
  91. package/src/i18n/index.ts +216 -216
  92. package/src/index.ts +10 -3
  93. package/src/marketplace/index.ts +223 -0
  94. package/src/memory/deepbrain.ts +108 -108
  95. package/src/memory/index.ts +34 -34
  96. package/src/plugins/index.ts +208 -208
  97. package/src/schema/oad.ts +155 -154
  98. package/src/skills/base.ts +16 -16
  99. package/src/skills/document.ts +100 -100
  100. package/src/skills/http.ts +35 -35
  101. package/src/skills/index.ts +27 -27
  102. package/src/skills/scheduler.ts +80 -80
  103. package/src/skills/webhook-trigger.ts +59 -59
  104. package/src/templates/code-reviewer.ts +34 -30
  105. package/src/templates/customer-service.ts +80 -76
  106. package/src/templates/data-analyst.ts +70 -66
  107. package/src/templates/executive-assistant.ts +71 -71
  108. package/src/templates/financial-advisor.ts +60 -60
  109. package/src/templates/knowledge-base.ts +31 -27
  110. package/src/templates/legal-assistant.ts +71 -71
  111. package/src/templates/sales-assistant.ts +79 -75
  112. package/src/templates/teacher.ts +79 -75
  113. package/src/testing/index.ts +181 -181
  114. package/src/tools/calculator.ts +73 -73
  115. package/src/tools/datetime.ts +149 -149
  116. package/src/tools/json-transform.ts +187 -187
  117. package/src/tools/mcp.ts +76 -76
  118. package/src/tools/text-analysis.ts +116 -116
  119. package/templates/Dockerfile +15 -15
  120. package/templates/code-reviewer/README.md +27 -27
  121. package/templates/code-reviewer/oad.yaml +41 -41
  122. package/templates/customer-service/README.md +22 -22
  123. package/templates/customer-service/oad.yaml +36 -36
  124. package/templates/docker-compose.yml +21 -21
  125. package/templates/ecommerce-assistant/README.md +45 -45
  126. package/templates/ecommerce-assistant/oad.yaml +47 -47
  127. package/templates/knowledge-base/README.md +28 -28
  128. package/templates/knowledge-base/oad.yaml +38 -38
  129. package/templates/sales-assistant/README.md +26 -26
  130. package/templates/sales-assistant/oad.yaml +43 -43
  131. package/templates/tech-support/README.md +43 -43
  132. package/templates/tech-support/oad.yaml +45 -45
  133. package/tests/a2a.test.ts +66 -66
  134. package/tests/agent.test.ts +72 -72
  135. package/tests/analytics.test.ts +50 -50
  136. package/tests/channel.test.ts +39 -39
  137. package/tests/e2e.test.ts +134 -134
  138. package/tests/errors.test.ts +83 -83
  139. package/tests/hitl.test.ts +71 -71
  140. package/tests/i18n.test.ts +41 -41
  141. package/tests/mcp.test.ts +54 -54
  142. package/tests/oad.test.ts +68 -68
  143. package/tests/performance.test.ts +115 -115
  144. package/tests/plugin.test.ts +74 -74
  145. package/tests/room.test.ts +106 -106
  146. package/tests/runtime.test.ts +42 -42
  147. package/tests/sandbox.test.ts +46 -46
  148. package/tests/security.test.ts +60 -60
  149. package/tests/templates.test.ts +77 -77
  150. package/tests/v070.test.ts +76 -76
  151. package/tests/versioning.test.ts +75 -75
  152. package/tests/voice.test.ts +61 -61
  153. package/tests/webhook.test.ts +29 -29
  154. package/tests/workflow.test.ts +143 -143
  155. package/tsconfig.json +19 -19
  156. package/vitest.config.ts +9 -9
  157. package/.github/workflows/ci.yml +0 -24
  158. package/dist/traces/index.d.ts +0 -49
  159. package/dist/traces/index.js +0 -102
  160. package/src/traces/index.ts +0 -132
@@ -1,143 +1,143 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { WorkflowEngine, WorkflowDefinition } from '../src/core/workflow';
3
- import { BaseSkill } from '../src/skills/base';
4
- import type { AgentContext, Message, SkillResult, MemoryStore } from '../src/core/types';
5
-
6
- class EchoSkill extends BaseSkill {
7
- name = 'echo';
8
- description = 'Echo input';
9
- async execute(_ctx: AgentContext, msg: Message): Promise<SkillResult> {
10
- return this.match(`echo:${msg.content}`, 1.0);
11
- }
12
- }
13
-
14
- class UpperSkill extends BaseSkill {
15
- name = 'upper';
16
- description = 'Uppercase';
17
- async execute(_ctx: AgentContext, msg: Message): Promise<SkillResult> {
18
- return this.match(msg.content.toUpperCase(), 1.0);
19
- }
20
- }
21
-
22
- class FailSkill extends BaseSkill {
23
- name = 'fail';
24
- description = 'Always fails';
25
- async execute(): Promise<SkillResult> {
26
- throw new Error('intentional failure');
27
- }
28
- }
29
-
30
- const mockMemory: MemoryStore = {
31
- get: async () => null,
32
- set: async () => {},
33
- getConversation: async () => [],
34
- addMessage: async () => {},
35
- clear: async () => {},
36
- };
37
-
38
- const mockContext: AgentContext = {
39
- agentName: 'test',
40
- sessionId: 'test-session',
41
- messages: [],
42
- memory: mockMemory,
43
- metadata: {},
44
- };
45
-
46
- describe('WorkflowEngine', () => {
47
- let engine: WorkflowEngine;
48
-
49
- beforeEach(() => {
50
- engine = new WorkflowEngine();
51
- engine.registerSkill(new EchoSkill());
52
- engine.registerSkill(new UpperSkill());
53
- engine.registerSkill(new FailSkill());
54
- });
55
-
56
- it('should register and list workflows', () => {
57
- const wf: WorkflowDefinition = { name: 'test', steps: [] };
58
- engine.registerWorkflow(wf);
59
- expect(engine.listWorkflows()).toHaveLength(1);
60
- expect(engine.getWorkflow('test')).toBeDefined();
61
- });
62
-
63
- it('should run sequential steps', async () => {
64
- const wf: WorkflowDefinition = {
65
- name: 'seq',
66
- steps: [
67
- { id: 's1', type: 'skill', name: 'echo' },
68
- { id: 's2', type: 'skill', name: 'upper' },
69
- ],
70
- };
71
- engine.registerWorkflow(wf);
72
- const result = await engine.run('seq', mockContext, 'hello');
73
- expect(result.status).toBe('completed');
74
- expect(result.steps).toHaveLength(2);
75
- });
76
-
77
- it('should handle parallel steps', async () => {
78
- const wf: WorkflowDefinition = {
79
- name: 'par',
80
- steps: [{
81
- id: 'p1', type: 'parallel', name: 'parallel',
82
- parallel: [
83
- { id: 's1', type: 'skill', name: 'echo' },
84
- { id: 's2', type: 'skill', name: 'upper' },
85
- ],
86
- }],
87
- };
88
- engine.registerWorkflow(wf);
89
- const result = await engine.run('par', mockContext, 'test');
90
- expect(result.status).toBe('completed');
91
- });
92
-
93
- it('should handle conditional branching', async () => {
94
- const wf: WorkflowDefinition = {
95
- name: 'cond',
96
- steps: [{
97
- id: 'c1', type: 'condition', name: 'check',
98
- condition: 'contains:hello',
99
- branches: {
100
- if: [{ id: 's1', type: 'skill', name: 'echo' }],
101
- else: [{ id: 's2', type: 'skill', name: 'upper' }],
102
- },
103
- }],
104
- };
105
- engine.registerWorkflow(wf);
106
- const r1 = await engine.run('cond', mockContext, 'hello world');
107
- expect(r1.steps.find(s => s.stepId === 's1')).toBeDefined();
108
- });
109
-
110
- it('should handle step failures with stop policy', async () => {
111
- const wf: WorkflowDefinition = {
112
- name: 'fail-wf',
113
- onError: 'stop',
114
- steps: [
115
- { id: 's1', type: 'skill', name: 'fail' },
116
- { id: 's2', type: 'skill', name: 'echo' },
117
- ],
118
- };
119
- engine.registerWorkflow(wf);
120
- const result = await engine.run('fail-wf', mockContext, 'test');
121
- expect(result.status).toBe('failed');
122
- });
123
-
124
- it('should retry failed steps', async () => {
125
- const wf: WorkflowDefinition = {
126
- name: 'retry-wf',
127
- steps: [{ id: 's1', type: 'skill', name: 'fail', retries: 2 }],
128
- };
129
- engine.registerWorkflow(wf);
130
- const result = await engine.run('retry-wf', mockContext, 'test');
131
- expect(result.steps[0].status).toBe('error');
132
- });
133
-
134
- it('should throw on unknown workflow', async () => {
135
- await expect(engine.run('nonexistent', mockContext)).rejects.toThrow();
136
- });
137
-
138
- it('should unregister workflows', () => {
139
- engine.registerWorkflow({ name: 'temp', steps: [] });
140
- engine.unregisterWorkflow('temp');
141
- expect(engine.getWorkflow('temp')).toBeUndefined();
142
- });
143
- });
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { WorkflowEngine, WorkflowDefinition } from '../src/core/workflow';
3
+ import { BaseSkill } from '../src/skills/base';
4
+ import type { AgentContext, Message, SkillResult, MemoryStore } from '../src/core/types';
5
+
6
+ class EchoSkill extends BaseSkill {
7
+ name = 'echo';
8
+ description = 'Echo input';
9
+ async execute(_ctx: AgentContext, msg: Message): Promise<SkillResult> {
10
+ return this.match(`echo:${msg.content}`, 1.0);
11
+ }
12
+ }
13
+
14
+ class UpperSkill extends BaseSkill {
15
+ name = 'upper';
16
+ description = 'Uppercase';
17
+ async execute(_ctx: AgentContext, msg: Message): Promise<SkillResult> {
18
+ return this.match(msg.content.toUpperCase(), 1.0);
19
+ }
20
+ }
21
+
22
+ class FailSkill extends BaseSkill {
23
+ name = 'fail';
24
+ description = 'Always fails';
25
+ async execute(): Promise<SkillResult> {
26
+ throw new Error('intentional failure');
27
+ }
28
+ }
29
+
30
+ const mockMemory: MemoryStore = {
31
+ get: async () => null,
32
+ set: async () => {},
33
+ getConversation: async () => [],
34
+ addMessage: async () => {},
35
+ clear: async () => {},
36
+ };
37
+
38
+ const mockContext: AgentContext = {
39
+ agentName: 'test',
40
+ sessionId: 'test-session',
41
+ messages: [],
42
+ memory: mockMemory,
43
+ metadata: {},
44
+ };
45
+
46
+ describe('WorkflowEngine', () => {
47
+ let engine: WorkflowEngine;
48
+
49
+ beforeEach(() => {
50
+ engine = new WorkflowEngine();
51
+ engine.registerSkill(new EchoSkill());
52
+ engine.registerSkill(new UpperSkill());
53
+ engine.registerSkill(new FailSkill());
54
+ });
55
+
56
+ it('should register and list workflows', () => {
57
+ const wf: WorkflowDefinition = { name: 'test', steps: [] };
58
+ engine.registerWorkflow(wf);
59
+ expect(engine.listWorkflows()).toHaveLength(1);
60
+ expect(engine.getWorkflow('test')).toBeDefined();
61
+ });
62
+
63
+ it('should run sequential steps', async () => {
64
+ const wf: WorkflowDefinition = {
65
+ name: 'seq',
66
+ steps: [
67
+ { id: 's1', type: 'skill', name: 'echo' },
68
+ { id: 's2', type: 'skill', name: 'upper' },
69
+ ],
70
+ };
71
+ engine.registerWorkflow(wf);
72
+ const result = await engine.run('seq', mockContext, 'hello');
73
+ expect(result.status).toBe('completed');
74
+ expect(result.steps).toHaveLength(2);
75
+ });
76
+
77
+ it('should handle parallel steps', async () => {
78
+ const wf: WorkflowDefinition = {
79
+ name: 'par',
80
+ steps: [{
81
+ id: 'p1', type: 'parallel', name: 'parallel',
82
+ parallel: [
83
+ { id: 's1', type: 'skill', name: 'echo' },
84
+ { id: 's2', type: 'skill', name: 'upper' },
85
+ ],
86
+ }],
87
+ };
88
+ engine.registerWorkflow(wf);
89
+ const result = await engine.run('par', mockContext, 'test');
90
+ expect(result.status).toBe('completed');
91
+ });
92
+
93
+ it('should handle conditional branching', async () => {
94
+ const wf: WorkflowDefinition = {
95
+ name: 'cond',
96
+ steps: [{
97
+ id: 'c1', type: 'condition', name: 'check',
98
+ condition: 'contains:hello',
99
+ branches: {
100
+ if: [{ id: 's1', type: 'skill', name: 'echo' }],
101
+ else: [{ id: 's2', type: 'skill', name: 'upper' }],
102
+ },
103
+ }],
104
+ };
105
+ engine.registerWorkflow(wf);
106
+ const r1 = await engine.run('cond', mockContext, 'hello world');
107
+ expect(r1.steps.find(s => s.stepId === 's1')).toBeDefined();
108
+ });
109
+
110
+ it('should handle step failures with stop policy', async () => {
111
+ const wf: WorkflowDefinition = {
112
+ name: 'fail-wf',
113
+ onError: 'stop',
114
+ steps: [
115
+ { id: 's1', type: 'skill', name: 'fail' },
116
+ { id: 's2', type: 'skill', name: 'echo' },
117
+ ],
118
+ };
119
+ engine.registerWorkflow(wf);
120
+ const result = await engine.run('fail-wf', mockContext, 'test');
121
+ expect(result.status).toBe('failed');
122
+ });
123
+
124
+ it('should retry failed steps', async () => {
125
+ const wf: WorkflowDefinition = {
126
+ name: 'retry-wf',
127
+ steps: [{ id: 's1', type: 'skill', name: 'fail', retries: 2 }],
128
+ };
129
+ engine.registerWorkflow(wf);
130
+ const result = await engine.run('retry-wf', mockContext, 'test');
131
+ expect(result.steps[0].status).toBe('error');
132
+ });
133
+
134
+ it('should throw on unknown workflow', async () => {
135
+ await expect(engine.run('nonexistent', mockContext)).rejects.toThrow();
136
+ });
137
+
138
+ it('should unregister workflows', () => {
139
+ engine.registerWorkflow({ name: 'temp', steps: [] });
140
+ engine.unregisterWorkflow('temp');
141
+ expect(engine.getWorkflow('temp')).toBeUndefined();
142
+ });
143
+ });
package/tsconfig.json CHANGED
@@ -1,19 +1,19 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "commonjs",
5
- "lib": ["ES2022"],
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "resolveJsonModule": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true
16
- },
17
- "include": ["src/**/*"],
18
- "exclude": ["node_modules", "dist", "tests"]
19
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "commonjs",
5
+ "lib": ["ES2022"],
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist", "tests"]
19
+ }
package/vitest.config.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: true,
6
- environment: 'node',
7
- include: ['tests/**/*.test.ts'],
8
- },
9
- });
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['tests/**/*.test.ts'],
8
+ },
9
+ });
@@ -1,24 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
-
9
- jobs:
10
- test:
11
- runs-on: ubuntu-latest
12
- strategy:
13
- matrix:
14
- node-version: [18, 20, 22]
15
- steps:
16
- - uses: actions/checkout@v4
17
- - uses: actions/setup-node@v4
18
- with:
19
- node-version: ${{ matrix.node-version }}
20
- - run: npm ci
21
- - run: npm run build --if-present
22
- - run: npx vitest run --reporter=verbose
23
- env:
24
- CI: true
@@ -1,49 +0,0 @@
1
- /**
2
- * OPC Agent Traces — Structured logging for agent actions.
3
- *
4
- * Collects traces that can be fed to DeepBrain's learn() API.
5
- * Inspired by OpenTelemetry spans.
6
- */
7
- export interface Span {
8
- traceId: string;
9
- spanId: string;
10
- name: string;
11
- startTime: Date;
12
- endTime?: Date;
13
- attributes: Record<string, string | number | boolean>;
14
- events: SpanEvent[];
15
- status: 'ok' | 'error' | 'unset';
16
- }
17
- export interface SpanEvent {
18
- name: string;
19
- timestamp: Date;
20
- attributes?: Record<string, string | number | boolean>;
21
- }
22
- export interface TraceExporter {
23
- export(spans: Span[]): Promise<void>;
24
- }
25
- /** In-memory buffer that holds spans until flushed */
26
- export declare class TraceCollector {
27
- private spans;
28
- private exporters;
29
- private maxBufferSize;
30
- constructor(maxBufferSize?: number);
31
- addExporter(exporter: TraceExporter): void;
32
- startSpan(name: string, attributes?: Record<string, string | number | boolean>): Span;
33
- endSpan(span: Span, status?: 'ok' | 'error'): void;
34
- addEvent(span: Span, name: string, attributes?: Record<string, string | number | boolean>): void;
35
- flush(): Promise<number>;
36
- getBufferedSpans(): readonly Span[];
37
- get bufferedCount(): number;
38
- }
39
- /** Console exporter for development */
40
- export declare class ConsoleExporter implements TraceExporter {
41
- export(spans: Span[]): Promise<void>;
42
- }
43
- /** DeepBrain exporter — sends traces to DeepBrain learn() */
44
- export declare class DeepBrainExporter implements TraceExporter {
45
- private learnEndpoint;
46
- constructor(deepbrainUrl?: string);
47
- export(spans: Span[]): Promise<void>;
48
- }
49
- //# sourceMappingURL=index.d.ts.map
@@ -1,102 +0,0 @@
1
- "use strict";
2
- /**
3
- * OPC Agent Traces — Structured logging for agent actions.
4
- *
5
- * Collects traces that can be fed to DeepBrain's learn() API.
6
- * Inspired by OpenTelemetry spans.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.DeepBrainExporter = exports.ConsoleExporter = exports.TraceCollector = void 0;
10
- /** In-memory buffer that holds spans until flushed */
11
- class TraceCollector {
12
- spans = [];
13
- exporters = [];
14
- maxBufferSize;
15
- constructor(maxBufferSize = 100) {
16
- this.maxBufferSize = maxBufferSize;
17
- }
18
- addExporter(exporter) {
19
- this.exporters.push(exporter);
20
- }
21
- startSpan(name, attributes = {}) {
22
- const span = {
23
- traceId: crypto.randomUUID(),
24
- spanId: crypto.randomUUID().slice(0, 16),
25
- name,
26
- startTime: new Date(),
27
- attributes,
28
- events: [],
29
- status: 'unset',
30
- };
31
- this.spans.push(span);
32
- if (this.spans.length >= this.maxBufferSize) {
33
- this.flush().catch(() => { }); // Best effort
34
- }
35
- return span;
36
- }
37
- endSpan(span, status = 'ok') {
38
- span.endTime = new Date();
39
- span.status = status;
40
- }
41
- addEvent(span, name, attributes) {
42
- span.events.push({ name, timestamp: new Date(), attributes });
43
- }
44
- async flush() {
45
- const toExport = [...this.spans];
46
- this.spans = [];
47
- for (const exporter of this.exporters) {
48
- await exporter.export(toExport);
49
- }
50
- return toExport.length;
51
- }
52
- getBufferedSpans() {
53
- return this.spans;
54
- }
55
- get bufferedCount() {
56
- return this.spans.length;
57
- }
58
- }
59
- exports.TraceCollector = TraceCollector;
60
- /** Console exporter for development */
61
- class ConsoleExporter {
62
- async export(spans) {
63
- for (const span of spans) {
64
- const duration = span.endTime
65
- ? `${span.endTime.getTime() - span.startTime.getTime()}ms`
66
- : 'ongoing';
67
- console.log(`[TRACE] ${span.name} (${duration}) [${span.status}]`);
68
- }
69
- }
70
- }
71
- exports.ConsoleExporter = ConsoleExporter;
72
- /** DeepBrain exporter — sends traces to DeepBrain learn() */
73
- class DeepBrainExporter {
74
- learnEndpoint;
75
- constructor(deepbrainUrl = 'http://localhost:3333') {
76
- this.learnEndpoint = `${deepbrainUrl}/api/learn`;
77
- }
78
- async export(spans) {
79
- for (const span of spans) {
80
- try {
81
- await fetch(this.learnEndpoint, {
82
- method: 'POST',
83
- headers: { 'Content-Type': 'application/json' },
84
- body: JSON.stringify({
85
- action: span.name,
86
- result: span.status === 'ok' ? 'success' : 'error',
87
- context: {
88
- ...span.attributes,
89
- duration: span.endTime ? span.endTime.getTime() - span.startTime.getTime() : null,
90
- events: span.events.map(e => e.name),
91
- },
92
- }),
93
- });
94
- }
95
- catch {
96
- // Best effort — don't break agent if brain is down
97
- }
98
- }
99
- }
100
- }
101
- exports.DeepBrainExporter = DeepBrainExporter;
102
- //# sourceMappingURL=index.js.map
@@ -1,132 +0,0 @@
1
- /**
2
- * OPC Agent Traces — Structured logging for agent actions.
3
- *
4
- * Collects traces that can be fed to DeepBrain's learn() API.
5
- * Inspired by OpenTelemetry spans.
6
- */
7
-
8
- export interface Span {
9
- traceId: string;
10
- spanId: string;
11
- name: string;
12
- startTime: Date;
13
- endTime?: Date;
14
- attributes: Record<string, string | number | boolean>;
15
- events: SpanEvent[];
16
- status: 'ok' | 'error' | 'unset';
17
- }
18
-
19
- export interface SpanEvent {
20
- name: string;
21
- timestamp: Date;
22
- attributes?: Record<string, string | number | boolean>;
23
- }
24
-
25
- export interface TraceExporter {
26
- export(spans: Span[]): Promise<void>;
27
- }
28
-
29
- /** In-memory buffer that holds spans until flushed */
30
- export class TraceCollector {
31
- private spans: Span[] = [];
32
- private exporters: TraceExporter[] = [];
33
- private maxBufferSize: number;
34
-
35
- constructor(maxBufferSize = 100) {
36
- this.maxBufferSize = maxBufferSize;
37
- }
38
-
39
- addExporter(exporter: TraceExporter): void {
40
- this.exporters.push(exporter);
41
- }
42
-
43
- startSpan(name: string, attributes: Record<string, string | number | boolean> = {}): Span {
44
- const span: Span = {
45
- traceId: crypto.randomUUID(),
46
- spanId: crypto.randomUUID().slice(0, 16),
47
- name,
48
- startTime: new Date(),
49
- attributes,
50
- events: [],
51
- status: 'unset',
52
- };
53
- this.spans.push(span);
54
-
55
- if (this.spans.length >= this.maxBufferSize) {
56
- this.flush().catch(() => {}); // Best effort
57
- }
58
-
59
- return span;
60
- }
61
-
62
- endSpan(span: Span, status: 'ok' | 'error' = 'ok'): void {
63
- span.endTime = new Date();
64
- span.status = status;
65
- }
66
-
67
- addEvent(span: Span, name: string, attributes?: Record<string, string | number | boolean>): void {
68
- span.events.push({ name, timestamp: new Date(), attributes });
69
- }
70
-
71
- async flush(): Promise<number> {
72
- const toExport = [...this.spans];
73
- this.spans = [];
74
-
75
- for (const exporter of this.exporters) {
76
- await exporter.export(toExport);
77
- }
78
-
79
- return toExport.length;
80
- }
81
-
82
- getBufferedSpans(): readonly Span[] {
83
- return this.spans;
84
- }
85
-
86
- get bufferedCount(): number {
87
- return this.spans.length;
88
- }
89
- }
90
-
91
- /** Console exporter for development */
92
- export class ConsoleExporter implements TraceExporter {
93
- async export(spans: Span[]): Promise<void> {
94
- for (const span of spans) {
95
- const duration = span.endTime
96
- ? `${span.endTime.getTime() - span.startTime.getTime()}ms`
97
- : 'ongoing';
98
- console.log(`[TRACE] ${span.name} (${duration}) [${span.status}]`);
99
- }
100
- }
101
- }
102
-
103
- /** DeepBrain exporter — sends traces to DeepBrain learn() */
104
- export class DeepBrainExporter implements TraceExporter {
105
- private learnEndpoint: string;
106
-
107
- constructor(deepbrainUrl: string = 'http://localhost:3333') {
108
- this.learnEndpoint = `${deepbrainUrl}/api/learn`;
109
- }
110
-
111
- async export(spans: Span[]): Promise<void> {
112
- for (const span of spans) {
113
- try {
114
- await fetch(this.learnEndpoint, {
115
- method: 'POST',
116
- headers: { 'Content-Type': 'application/json' },
117
- body: JSON.stringify({
118
- action: span.name,
119
- result: span.status === 'ok' ? 'success' : 'error',
120
- context: {
121
- ...span.attributes,
122
- duration: span.endTime ? span.endTime.getTime() - span.startTime.getTime() : null,
123
- events: span.events.map(e => e.name),
124
- },
125
- }),
126
- });
127
- } catch {
128
- // Best effort — don't break agent if brain is down
129
- }
130
- }
131
- }
132
- }