opc-agent 1.3.2 → 2.0.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 (226) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +14 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  4. package/.github/workflows/ci.yml +24 -0
  5. package/CHANGELOG.md +48 -63
  6. package/CONTRIBUTING.md +21 -60
  7. package/README.md +284 -348
  8. package/README.zh-CN.md +415 -415
  9. package/dist/channels/slack.js +93 -10
  10. package/dist/channels/telegram.d.ts +30 -9
  11. package/dist/channels/telegram.js +125 -33
  12. package/dist/channels/web.d.ts +10 -0
  13. package/dist/channels/web.js +33 -2
  14. package/dist/cli.js +667 -65
  15. package/dist/core/agent.d.ts +23 -0
  16. package/dist/core/agent.js +120 -3
  17. package/dist/core/runtime.d.ts +5 -0
  18. package/dist/core/runtime.js +71 -0
  19. package/dist/core/scheduler.d.ts +52 -0
  20. package/dist/core/scheduler.js +168 -0
  21. package/dist/core/subagent.d.ts +28 -0
  22. package/dist/core/subagent.js +65 -0
  23. package/dist/daemon.d.ts +3 -0
  24. package/dist/daemon.js +134 -0
  25. package/dist/deploy/hermes.js +22 -22
  26. package/dist/deploy/openclaw.js +31 -40
  27. package/dist/index.d.ts +10 -10
  28. package/dist/index.js +22 -15
  29. package/dist/providers/index.d.ts +6 -2
  30. package/dist/providers/index.js +22 -9
  31. package/dist/schema/oad.d.ts +180 -6
  32. package/dist/schema/oad.js +12 -1
  33. package/dist/skills/auto-learn.d.ts +28 -0
  34. package/dist/skills/auto-learn.js +257 -0
  35. package/dist/templates/code-reviewer.d.ts +0 -8
  36. package/dist/templates/code-reviewer.js +5 -9
  37. package/dist/templates/customer-service.d.ts +0 -8
  38. package/dist/templates/customer-service.js +2 -6
  39. package/dist/templates/data-analyst.d.ts +0 -8
  40. package/dist/templates/data-analyst.js +5 -9
  41. package/dist/templates/knowledge-base.d.ts +0 -8
  42. package/dist/templates/knowledge-base.js +2 -6
  43. package/dist/templates/sales-assistant.d.ts +0 -8
  44. package/dist/templates/sales-assistant.js +4 -8
  45. package/dist/templates/teacher.d.ts +0 -8
  46. package/dist/templates/teacher.js +6 -10
  47. package/dist/tools/builtin/datetime.d.ts +3 -0
  48. package/dist/tools/builtin/datetime.js +44 -0
  49. package/dist/tools/builtin/file.d.ts +3 -0
  50. package/dist/tools/builtin/file.js +151 -0
  51. package/dist/tools/builtin/index.d.ts +15 -0
  52. package/dist/tools/builtin/index.js +30 -0
  53. package/dist/tools/builtin/shell.d.ts +3 -0
  54. package/dist/tools/builtin/shell.js +43 -0
  55. package/dist/tools/builtin/web.d.ts +3 -0
  56. package/dist/tools/builtin/web.js +37 -0
  57. package/dist/tools/mcp-client.d.ts +24 -0
  58. package/dist/tools/mcp-client.js +119 -0
  59. package/dist/traces/index.d.ts +49 -0
  60. package/dist/traces/index.js +102 -0
  61. package/docs/.vitepress/config.ts +103 -103
  62. package/docs/api/cli.md +48 -48
  63. package/docs/api/oad-schema.md +64 -64
  64. package/docs/api/sdk.md +80 -80
  65. package/docs/guide/concepts.md +51 -51
  66. package/docs/guide/configuration.md +79 -79
  67. package/docs/guide/deployment.md +42 -42
  68. package/docs/guide/getting-started.md +44 -44
  69. package/docs/guide/templates.md +28 -28
  70. package/docs/guide/testing.md +84 -84
  71. package/docs/index.md +27 -27
  72. package/docs/zh/api/cli.md +54 -54
  73. package/docs/zh/api/oad-schema.md +87 -87
  74. package/docs/zh/api/sdk.md +102 -102
  75. package/docs/zh/guide/concepts.md +104 -104
  76. package/docs/zh/guide/configuration.md +135 -135
  77. package/docs/zh/guide/deployment.md +81 -81
  78. package/docs/zh/guide/getting-started.md +82 -82
  79. package/docs/zh/guide/templates.md +84 -84
  80. package/docs/zh/guide/testing.md +88 -88
  81. package/docs/zh/index.md +27 -27
  82. package/examples/README.md +22 -0
  83. package/examples/basic-agent.ts +90 -0
  84. package/examples/brain-integration.ts +71 -0
  85. package/examples/customer-service-demo/README.md +90 -90
  86. package/examples/customer-service-demo/oad.yaml +107 -107
  87. package/examples/multi-channel.ts +74 -0
  88. package/package.json +1 -1
  89. package/src/analytics/index.ts +66 -66
  90. package/src/channels/discord.ts +192 -192
  91. package/src/channels/email.ts +177 -177
  92. package/src/channels/feishu.ts +236 -236
  93. package/src/channels/index.ts +15 -15
  94. package/src/channels/slack.ts +217 -160
  95. package/src/channels/telegram.ts +155 -33
  96. package/src/channels/voice.ts +106 -106
  97. package/src/channels/web.ts +38 -2
  98. package/src/channels/webhook.ts +199 -199
  99. package/src/channels/websocket.ts +87 -87
  100. package/src/channels/wechat.ts +149 -149
  101. package/src/cli.ts +697 -63
  102. package/src/core/a2a.ts +143 -143
  103. package/src/core/agent.ts +146 -3
  104. package/src/core/analytics-engine.ts +186 -186
  105. package/src/core/auth.ts +57 -57
  106. package/src/core/cache.ts +141 -141
  107. package/src/core/compose.ts +77 -77
  108. package/src/core/config.ts +14 -14
  109. package/src/core/errors.ts +148 -148
  110. package/src/core/hitl.ts +138 -138
  111. package/src/core/logger.ts +57 -57
  112. package/src/core/orchestrator.ts +215 -215
  113. package/src/core/performance.ts +187 -187
  114. package/src/core/rate-limiter.ts +128 -128
  115. package/src/core/room.ts +109 -109
  116. package/src/core/runtime.ts +230 -152
  117. package/src/core/sandbox.ts +101 -101
  118. package/src/core/scheduler.ts +187 -0
  119. package/src/core/security.ts +171 -171
  120. package/src/core/subagent.ts +98 -0
  121. package/src/core/types.ts +68 -68
  122. package/src/core/versioning.ts +106 -106
  123. package/src/core/watch.ts +178 -178
  124. package/src/core/workflow.ts +235 -235
  125. package/src/daemon.ts +96 -0
  126. package/src/deploy/hermes.ts +156 -156
  127. package/src/deploy/openclaw.ts +190 -200
  128. package/src/i18n/index.ts +216 -216
  129. package/src/index.ts +14 -10
  130. package/src/memory/deepbrain.ts +108 -108
  131. package/src/memory/index.ts +34 -34
  132. package/src/plugins/index.ts +208 -208
  133. package/src/providers/index.ts +354 -331
  134. package/src/schema/oad.ts +14 -2
  135. package/src/skills/auto-learn.ts +262 -0
  136. package/src/skills/base.ts +16 -16
  137. package/src/skills/document.ts +100 -100
  138. package/src/skills/http.ts +35 -35
  139. package/src/skills/index.ts +27 -27
  140. package/src/skills/scheduler.ts +80 -80
  141. package/src/skills/webhook-trigger.ts +59 -59
  142. package/src/templates/code-reviewer.ts +30 -34
  143. package/src/templates/customer-service.ts +76 -80
  144. package/src/templates/data-analyst.ts +66 -70
  145. package/src/templates/executive-assistant.ts +71 -71
  146. package/src/templates/financial-advisor.ts +60 -60
  147. package/src/templates/knowledge-base.ts +27 -31
  148. package/src/templates/legal-assistant.ts +71 -71
  149. package/src/templates/sales-assistant.ts +75 -79
  150. package/src/templates/teacher.ts +75 -79
  151. package/src/testing/index.ts +181 -181
  152. package/src/tools/builtin/datetime.ts +41 -0
  153. package/src/tools/builtin/file.ts +107 -0
  154. package/src/tools/builtin/index.ts +28 -0
  155. package/src/tools/builtin/shell.ts +43 -0
  156. package/src/tools/builtin/web.ts +35 -0
  157. package/src/tools/calculator.ts +73 -73
  158. package/src/tools/datetime.ts +149 -149
  159. package/src/tools/json-transform.ts +187 -187
  160. package/src/tools/mcp-client.ts +131 -0
  161. package/src/tools/mcp.ts +76 -76
  162. package/src/tools/text-analysis.ts +116 -116
  163. package/src/traces/index.ts +132 -0
  164. package/templates/Dockerfile +15 -15
  165. package/templates/code-reviewer/README.md +27 -27
  166. package/templates/code-reviewer/oad.yaml +41 -41
  167. package/templates/customer-service/README.md +22 -22
  168. package/templates/customer-service/oad.yaml +36 -36
  169. package/templates/docker-compose.yml +21 -21
  170. package/templates/ecommerce-assistant/README.md +45 -45
  171. package/templates/ecommerce-assistant/oad.yaml +47 -47
  172. package/templates/knowledge-base/README.md +28 -28
  173. package/templates/knowledge-base/oad.yaml +38 -38
  174. package/templates/sales-assistant/README.md +26 -26
  175. package/templates/sales-assistant/oad.yaml +43 -43
  176. package/templates/tech-support/README.md +43 -43
  177. package/templates/tech-support/oad.yaml +45 -45
  178. package/test-agent/Dockerfile +9 -0
  179. package/test-agent/README.md +50 -0
  180. package/test-agent/agent.yaml +23 -0
  181. package/test-agent/docker-compose.yml +11 -0
  182. package/test-agent/oad.yaml +31 -0
  183. package/test-agent/package-lock.json +1492 -0
  184. package/test-agent/package.json +18 -0
  185. package/test-agent/src/index.ts +24 -0
  186. package/test-agent/src/skills/echo.ts +15 -0
  187. package/test-agent/tsconfig.json +25 -0
  188. package/tests/a2a.test.ts +66 -66
  189. package/tests/agent.test.ts +72 -72
  190. package/tests/analytics.test.ts +50 -50
  191. package/tests/auto-learn.test.ts +105 -0
  192. package/tests/builtin-tools.test.ts +83 -0
  193. package/tests/channel.test.ts +39 -39
  194. package/tests/cli.test.ts +46 -0
  195. package/tests/e2e.test.ts +134 -134
  196. package/tests/errors.test.ts +83 -83
  197. package/tests/hitl.test.ts +71 -71
  198. package/tests/i18n.test.ts +41 -41
  199. package/tests/mcp.test.ts +54 -54
  200. package/tests/oad.test.ts +68 -68
  201. package/tests/performance.test.ts +115 -115
  202. package/tests/plugin.test.ts +74 -74
  203. package/tests/room.test.ts +106 -106
  204. package/tests/runtime.test.ts +42 -42
  205. package/tests/sandbox.test.ts +46 -46
  206. package/tests/security.test.ts +60 -60
  207. package/tests/subagent.test.ts +130 -0
  208. package/tests/telegram-discord.test.ts +60 -0
  209. package/tests/templates.test.ts +77 -77
  210. package/tests/v070.test.ts +76 -76
  211. package/tests/versioning.test.ts +75 -75
  212. package/tests/voice.test.ts +61 -61
  213. package/tests/webhook.test.ts +29 -29
  214. package/tests/workflow.test.ts +143 -143
  215. package/tsconfig.json +19 -19
  216. package/vitest.config.ts +9 -9
  217. package/dist/core/dashboard.d.ts +0 -35
  218. package/dist/core/dashboard.js +0 -157
  219. package/dist/core/priority.d.ts +0 -52
  220. package/dist/core/priority.js +0 -102
  221. package/src/core/dashboard.ts +0 -219
  222. package/src/core/priority.ts +0 -140
  223. package/src/dtv/data.ts +0 -29
  224. package/src/dtv/trust.ts +0 -43
  225. package/src/dtv/value.ts +0 -47
  226. package/src/marketplace/index.ts +0 -223
@@ -1,115 +1,115 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { ConnectionPool, RequestBatcher, LazyLoader } from '../src/core/performance';
3
-
4
- describe('ConnectionPool', () => {
5
- it('should acquire and release connections', () => {
6
- const pool = new ConnectionPool(3);
7
- const conn = pool.acquire('openai');
8
- expect(conn.inUse).toBe(true);
9
- pool.release(conn.id);
10
- const stats = pool.getStats();
11
- expect(stats['openai'].total).toBe(1);
12
- expect(stats['openai'].inUse).toBe(0);
13
- });
14
-
15
- it('should reuse released connections', () => {
16
- const pool = new ConnectionPool(2);
17
- const c1 = pool.acquire('openai');
18
- pool.release(c1.id);
19
- const c2 = pool.acquire('openai');
20
- expect(c2.id).toBe(c1.id);
21
- });
22
-
23
- it('should drain all connections', () => {
24
- const pool = new ConnectionPool();
25
- pool.acquire('openai');
26
- pool.acquire('deepseek');
27
- pool.drain();
28
- expect(pool.getStats()).toEqual({});
29
- });
30
- });
31
-
32
- describe('RequestBatcher', () => {
33
- it('should batch requests', async () => {
34
- const batcher = new RequestBatcher<string>(
35
- async (batch) => batch.map(s => s.toUpperCase()),
36
- 2,
37
- 10,
38
- );
39
-
40
- const [r1, r2] = await Promise.all([
41
- batcher.add('hello'),
42
- batcher.add('world'),
43
- ]);
44
- expect(r1).toBe('HELLO');
45
- expect(r2).toBe('WORLD');
46
- });
47
-
48
- it('should flush on timer', async () => {
49
- const batcher = new RequestBatcher<number>(
50
- async (batch) => batch.map(n => n * 2),
51
- 10,
52
- 20,
53
- );
54
-
55
- const result = await batcher.add(5);
56
- expect(result).toBe(10);
57
- });
58
-
59
- it('should track pending count', () => {
60
- const batcher = new RequestBatcher<string>(
61
- async (batch) => batch,
62
- 100,
63
- 10000,
64
- );
65
- batcher.add('a');
66
- batcher.add('b');
67
- expect(batcher.pending).toBe(2);
68
- });
69
- });
70
-
71
- describe('LazyLoader', () => {
72
- it('should lazily load items', async () => {
73
- const loader = new LazyLoader<string>();
74
- let loadCount = 0;
75
- loader.register('greeting', async () => { loadCount++; return 'hello'; });
76
-
77
- expect(loader.isLoaded('greeting')).toBe(false);
78
- const val = await loader.get('greeting');
79
- expect(val).toBe('hello');
80
- expect(loader.isLoaded('greeting')).toBe(true);
81
-
82
- // Second call should use cache
83
- await loader.get('greeting');
84
- expect(loadCount).toBe(1);
85
- });
86
-
87
- it('should throw for unregistered items', async () => {
88
- const loader = new LazyLoader();
89
- await expect(loader.get('unknown')).rejects.toThrow('No loader registered');
90
- });
91
-
92
- it('should evict and reload', async () => {
93
- const loader = new LazyLoader<number>();
94
- let count = 0;
95
- loader.register('counter', async () => ++count);
96
-
97
- await loader.get('counter');
98
- expect(loader.loadedCount).toBe(1);
99
- loader.evict('counter');
100
- expect(loader.loadedCount).toBe(0);
101
- await loader.get('counter');
102
- expect(count).toBe(2);
103
- });
104
-
105
- it('should clear all', async () => {
106
- const loader = new LazyLoader<string>();
107
- loader.register('a', async () => 'a');
108
- loader.register('b', async () => 'b');
109
- await loader.get('a');
110
- await loader.get('b');
111
- loader.clear();
112
- expect(loader.loadedCount).toBe(0);
113
- expect(loader.registeredCount).toBe(2);
114
- });
115
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ConnectionPool, RequestBatcher, LazyLoader } from '../src/core/performance';
3
+
4
+ describe('ConnectionPool', () => {
5
+ it('should acquire and release connections', () => {
6
+ const pool = new ConnectionPool(3);
7
+ const conn = pool.acquire('openai');
8
+ expect(conn.inUse).toBe(true);
9
+ pool.release(conn.id);
10
+ const stats = pool.getStats();
11
+ expect(stats['openai'].total).toBe(1);
12
+ expect(stats['openai'].inUse).toBe(0);
13
+ });
14
+
15
+ it('should reuse released connections', () => {
16
+ const pool = new ConnectionPool(2);
17
+ const c1 = pool.acquire('openai');
18
+ pool.release(c1.id);
19
+ const c2 = pool.acquire('openai');
20
+ expect(c2.id).toBe(c1.id);
21
+ });
22
+
23
+ it('should drain all connections', () => {
24
+ const pool = new ConnectionPool();
25
+ pool.acquire('openai');
26
+ pool.acquire('deepseek');
27
+ pool.drain();
28
+ expect(pool.getStats()).toEqual({});
29
+ });
30
+ });
31
+
32
+ describe('RequestBatcher', () => {
33
+ it('should batch requests', async () => {
34
+ const batcher = new RequestBatcher<string>(
35
+ async (batch) => batch.map(s => s.toUpperCase()),
36
+ 2,
37
+ 10,
38
+ );
39
+
40
+ const [r1, r2] = await Promise.all([
41
+ batcher.add('hello'),
42
+ batcher.add('world'),
43
+ ]);
44
+ expect(r1).toBe('HELLO');
45
+ expect(r2).toBe('WORLD');
46
+ });
47
+
48
+ it('should flush on timer', async () => {
49
+ const batcher = new RequestBatcher<number>(
50
+ async (batch) => batch.map(n => n * 2),
51
+ 10,
52
+ 20,
53
+ );
54
+
55
+ const result = await batcher.add(5);
56
+ expect(result).toBe(10);
57
+ });
58
+
59
+ it('should track pending count', () => {
60
+ const batcher = new RequestBatcher<string>(
61
+ async (batch) => batch,
62
+ 100,
63
+ 10000,
64
+ );
65
+ batcher.add('a');
66
+ batcher.add('b');
67
+ expect(batcher.pending).toBe(2);
68
+ });
69
+ });
70
+
71
+ describe('LazyLoader', () => {
72
+ it('should lazily load items', async () => {
73
+ const loader = new LazyLoader<string>();
74
+ let loadCount = 0;
75
+ loader.register('greeting', async () => { loadCount++; return 'hello'; });
76
+
77
+ expect(loader.isLoaded('greeting')).toBe(false);
78
+ const val = await loader.get('greeting');
79
+ expect(val).toBe('hello');
80
+ expect(loader.isLoaded('greeting')).toBe(true);
81
+
82
+ // Second call should use cache
83
+ await loader.get('greeting');
84
+ expect(loadCount).toBe(1);
85
+ });
86
+
87
+ it('should throw for unregistered items', async () => {
88
+ const loader = new LazyLoader();
89
+ await expect(loader.get('unknown')).rejects.toThrow('No loader registered');
90
+ });
91
+
92
+ it('should evict and reload', async () => {
93
+ const loader = new LazyLoader<number>();
94
+ let count = 0;
95
+ loader.register('counter', async () => ++count);
96
+
97
+ await loader.get('counter');
98
+ expect(loader.loadedCount).toBe(1);
99
+ loader.evict('counter');
100
+ expect(loader.loadedCount).toBe(0);
101
+ await loader.get('counter');
102
+ expect(count).toBe(2);
103
+ });
104
+
105
+ it('should clear all', async () => {
106
+ const loader = new LazyLoader<string>();
107
+ loader.register('a', async () => 'a');
108
+ loader.register('b', async () => 'b');
109
+ await loader.get('a');
110
+ await loader.get('b');
111
+ loader.clear();
112
+ expect(loader.loadedCount).toBe(0);
113
+ expect(loader.registeredCount).toBe(2);
114
+ });
115
+ });
@@ -1,74 +1,74 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PluginManager } from '../src/plugins';
3
- import type { IPlugin } from '../src/plugins';
4
-
5
- describe('Plugin System', () => {
6
- it('should register and list plugins', () => {
7
- const pm = new PluginManager();
8
- const plugin: IPlugin = { name: 'test-plugin', version: '1.0.0', description: 'Test' };
9
- pm.register(plugin);
10
- expect(pm.has('test-plugin')).toBe(true);
11
- expect(pm.list().length).toBe(1);
12
- expect(pm.list()[0].name).toBe('test-plugin');
13
- });
14
-
15
- it('should run lifecycle hooks', async () => {
16
- const pm = new PluginManager();
17
- const calls: string[] = [];
18
-
19
- pm.register({
20
- name: 'hook-plugin',
21
- version: '1.0.0',
22
- hooks: {
23
- beforeInit: async () => { calls.push('beforeInit'); },
24
- afterInit: async () => { calls.push('afterInit'); },
25
- beforeShutdown: async () => { calls.push('beforeShutdown'); },
26
- },
27
- });
28
-
29
- await pm.runHook('beforeInit');
30
- await pm.runHook('afterInit');
31
- await pm.runHook('beforeShutdown');
32
- expect(calls).toEqual(['beforeInit', 'afterInit', 'beforeShutdown']);
33
- });
34
-
35
- it('should collect skills from plugins', () => {
36
- const pm = new PluginManager();
37
- pm.register({
38
- name: 'skill-plugin',
39
- version: '1.0.0',
40
- skills: [{
41
- name: 'test-skill',
42
- description: 'Test',
43
- execute: async () => ({ handled: false, confidence: 0 }),
44
- }],
45
- });
46
-
47
- expect(pm.getAllSkills().length).toBe(1);
48
- expect(pm.getAllSkills()[0].name).toBe('test-skill');
49
- });
50
-
51
- it('should unregister plugins', () => {
52
- const pm = new PluginManager();
53
- pm.register({ name: 'temp', version: '1.0.0' });
54
- pm.unregister('temp');
55
- expect(pm.has('temp')).toBe(false);
56
- });
57
-
58
- it('should run hooks from multiple plugins in order', async () => {
59
- const pm = new PluginManager();
60
- const order: string[] = [];
61
-
62
- pm.register({
63
- name: 'p1', version: '1.0.0',
64
- hooks: { beforeInit: async () => { order.push('p1'); } },
65
- });
66
- pm.register({
67
- name: 'p2', version: '1.0.0',
68
- hooks: { beforeInit: async () => { order.push('p2'); } },
69
- });
70
-
71
- await pm.runHook('beforeInit');
72
- expect(order).toEqual(['p1', 'p2']);
73
- });
74
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { PluginManager } from '../src/plugins';
3
+ import type { IPlugin } from '../src/plugins';
4
+
5
+ describe('Plugin System', () => {
6
+ it('should register and list plugins', () => {
7
+ const pm = new PluginManager();
8
+ const plugin: IPlugin = { name: 'test-plugin', version: '1.0.0', description: 'Test' };
9
+ pm.register(plugin);
10
+ expect(pm.has('test-plugin')).toBe(true);
11
+ expect(pm.list().length).toBe(1);
12
+ expect(pm.list()[0].name).toBe('test-plugin');
13
+ });
14
+
15
+ it('should run lifecycle hooks', async () => {
16
+ const pm = new PluginManager();
17
+ const calls: string[] = [];
18
+
19
+ pm.register({
20
+ name: 'hook-plugin',
21
+ version: '1.0.0',
22
+ hooks: {
23
+ beforeInit: async () => { calls.push('beforeInit'); },
24
+ afterInit: async () => { calls.push('afterInit'); },
25
+ beforeShutdown: async () => { calls.push('beforeShutdown'); },
26
+ },
27
+ });
28
+
29
+ await pm.runHook('beforeInit');
30
+ await pm.runHook('afterInit');
31
+ await pm.runHook('beforeShutdown');
32
+ expect(calls).toEqual(['beforeInit', 'afterInit', 'beforeShutdown']);
33
+ });
34
+
35
+ it('should collect skills from plugins', () => {
36
+ const pm = new PluginManager();
37
+ pm.register({
38
+ name: 'skill-plugin',
39
+ version: '1.0.0',
40
+ skills: [{
41
+ name: 'test-skill',
42
+ description: 'Test',
43
+ execute: async () => ({ handled: false, confidence: 0 }),
44
+ }],
45
+ });
46
+
47
+ expect(pm.getAllSkills().length).toBe(1);
48
+ expect(pm.getAllSkills()[0].name).toBe('test-skill');
49
+ });
50
+
51
+ it('should unregister plugins', () => {
52
+ const pm = new PluginManager();
53
+ pm.register({ name: 'temp', version: '1.0.0' });
54
+ pm.unregister('temp');
55
+ expect(pm.has('temp')).toBe(false);
56
+ });
57
+
58
+ it('should run hooks from multiple plugins in order', async () => {
59
+ const pm = new PluginManager();
60
+ const order: string[] = [];
61
+
62
+ pm.register({
63
+ name: 'p1', version: '1.0.0',
64
+ hooks: { beforeInit: async () => { order.push('p1'); } },
65
+ });
66
+ pm.register({
67
+ name: 'p2', version: '1.0.0',
68
+ hooks: { beforeInit: async () => { order.push('p2'); } },
69
+ });
70
+
71
+ await pm.runHook('beforeInit');
72
+ expect(order).toEqual(['p1', 'p2']);
73
+ });
74
+ });
@@ -1,106 +1,106 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Room } from '../src/core/room';
3
- import { BaseAgent } from '../src/core/agent';
4
-
5
- function makeAgent(name: string): BaseAgent {
6
- const agent = new BaseAgent({ name });
7
- // Synchronously set to ready by calling init
8
- return agent;
9
- }
10
-
11
- describe('Room System', () => {
12
- it('should create a room with a name', () => {
13
- const room = new Room('test-room');
14
- expect(room.name).toBe('test-room');
15
- expect(room.getAgents()).toEqual([]);
16
- });
17
-
18
- it('should add and remove agents', () => {
19
- const room = new Room('office');
20
- const agent = makeAgent('agent-1');
21
- room.addAgent(agent);
22
- expect(room.getAgents()).toEqual(['agent-1']);
23
- room.removeAgent('agent-1');
24
- expect(room.getAgents()).toEqual([]);
25
- });
26
-
27
- it('should emit events on join/leave', () => {
28
- const room = new Room('office');
29
- const events: string[] = [];
30
- room.on('agent:join', (name) => events.push(`join:${name}`));
31
- room.on('agent:leave', (name) => events.push(`leave:${name}`));
32
-
33
- const agent = makeAgent('a1');
34
- room.addAgent(agent);
35
- room.removeAgent('a1');
36
- expect(events).toEqual(['join:a1', 'leave:a1']);
37
- });
38
-
39
- it('should support topic subscriptions', () => {
40
- const room = new Room('office');
41
- room.subscribe('agent-1', 'alerts');
42
- room.subscribe('agent-2', 'alerts');
43
- expect(room.getSubscribers('alerts')).toEqual(['agent-1', 'agent-2']);
44
- room.unsubscribe('agent-1', 'alerts');
45
- expect(room.getSubscribers('alerts')).toEqual(['agent-2']);
46
- });
47
-
48
- it('should broadcast to all agents except sender', async () => {
49
- const room = new Room('office');
50
- const a1 = makeAgent('a1');
51
- const a2 = makeAgent('a2');
52
- await a1.init();
53
- await a2.init();
54
- room.addAgent(a1);
55
- room.addAgent(a2);
56
-
57
- const responses = await room.broadcast('a1', 'Hello everyone');
58
- expect(responses.length).toBe(1); // only a2 responds
59
- expect(responses[0].role).toBe('assistant');
60
- });
61
-
62
- it('should send direct messages', async () => {
63
- const room = new Room('office');
64
- const a1 = makeAgent('a1');
65
- const a2 = makeAgent('a2');
66
- await a1.init();
67
- await a2.init();
68
- room.addAgent(a1);
69
- room.addAgent(a2);
70
-
71
- const responses = await room.send({
72
- from: 'a1',
73
- to: 'a2',
74
- message: { id: 'm1', role: 'user', content: 'Hi a2', timestamp: Date.now() },
75
- });
76
- expect(responses.length).toBe(1);
77
- });
78
-
79
- it('should publish to topic subscribers only', async () => {
80
- const room = new Room('office');
81
- const a1 = makeAgent('a1');
82
- const a2 = makeAgent('a2');
83
- const a3 = makeAgent('a3');
84
- await a1.init();
85
- await a2.init();
86
- await a3.init();
87
- room.addAgent(a1);
88
- room.addAgent(a2);
89
- room.addAgent(a3);
90
-
91
- room.subscribe('a2', 'alerts');
92
- // a3 not subscribed
93
- const responses = await room.publishToTopic('a1', 'alerts', 'Alert!');
94
- expect(responses.length).toBe(1);
95
- });
96
-
97
- it('should remove agent from subscriptions on leave', () => {
98
- const room = new Room('office');
99
- room.subscribe('a1', 'topic1');
100
- room.subscribe('a1', 'topic2');
101
- expect(room.getSubscribers('topic1')).toContain('a1');
102
- room.removeAgent('a1');
103
- expect(room.getSubscribers('topic1')).not.toContain('a1');
104
- expect(room.getSubscribers('topic2')).not.toContain('a1');
105
- });
106
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Room } from '../src/core/room';
3
+ import { BaseAgent } from '../src/core/agent';
4
+
5
+ function makeAgent(name: string): BaseAgent {
6
+ const agent = new BaseAgent({ name });
7
+ // Synchronously set to ready by calling init
8
+ return agent;
9
+ }
10
+
11
+ describe('Room System', () => {
12
+ it('should create a room with a name', () => {
13
+ const room = new Room('test-room');
14
+ expect(room.name).toBe('test-room');
15
+ expect(room.getAgents()).toEqual([]);
16
+ });
17
+
18
+ it('should add and remove agents', () => {
19
+ const room = new Room('office');
20
+ const agent = makeAgent('agent-1');
21
+ room.addAgent(agent);
22
+ expect(room.getAgents()).toEqual(['agent-1']);
23
+ room.removeAgent('agent-1');
24
+ expect(room.getAgents()).toEqual([]);
25
+ });
26
+
27
+ it('should emit events on join/leave', () => {
28
+ const room = new Room('office');
29
+ const events: string[] = [];
30
+ room.on('agent:join', (name) => events.push(`join:${name}`));
31
+ room.on('agent:leave', (name) => events.push(`leave:${name}`));
32
+
33
+ const agent = makeAgent('a1');
34
+ room.addAgent(agent);
35
+ room.removeAgent('a1');
36
+ expect(events).toEqual(['join:a1', 'leave:a1']);
37
+ });
38
+
39
+ it('should support topic subscriptions', () => {
40
+ const room = new Room('office');
41
+ room.subscribe('agent-1', 'alerts');
42
+ room.subscribe('agent-2', 'alerts');
43
+ expect(room.getSubscribers('alerts')).toEqual(['agent-1', 'agent-2']);
44
+ room.unsubscribe('agent-1', 'alerts');
45
+ expect(room.getSubscribers('alerts')).toEqual(['agent-2']);
46
+ });
47
+
48
+ it('should broadcast to all agents except sender', async () => {
49
+ const room = new Room('office');
50
+ const a1 = makeAgent('a1');
51
+ const a2 = makeAgent('a2');
52
+ await a1.init();
53
+ await a2.init();
54
+ room.addAgent(a1);
55
+ room.addAgent(a2);
56
+
57
+ const responses = await room.broadcast('a1', 'Hello everyone');
58
+ expect(responses.length).toBe(1); // only a2 responds
59
+ expect(responses[0].role).toBe('assistant');
60
+ });
61
+
62
+ it('should send direct messages', async () => {
63
+ const room = new Room('office');
64
+ const a1 = makeAgent('a1');
65
+ const a2 = makeAgent('a2');
66
+ await a1.init();
67
+ await a2.init();
68
+ room.addAgent(a1);
69
+ room.addAgent(a2);
70
+
71
+ const responses = await room.send({
72
+ from: 'a1',
73
+ to: 'a2',
74
+ message: { id: 'm1', role: 'user', content: 'Hi a2', timestamp: Date.now() },
75
+ });
76
+ expect(responses.length).toBe(1);
77
+ });
78
+
79
+ it('should publish to topic subscribers only', async () => {
80
+ const room = new Room('office');
81
+ const a1 = makeAgent('a1');
82
+ const a2 = makeAgent('a2');
83
+ const a3 = makeAgent('a3');
84
+ await a1.init();
85
+ await a2.init();
86
+ await a3.init();
87
+ room.addAgent(a1);
88
+ room.addAgent(a2);
89
+ room.addAgent(a3);
90
+
91
+ room.subscribe('a2', 'alerts');
92
+ // a3 not subscribed
93
+ const responses = await room.publishToTopic('a1', 'alerts', 'Alert!');
94
+ expect(responses.length).toBe(1);
95
+ });
96
+
97
+ it('should remove agent from subscriptions on leave', () => {
98
+ const room = new Room('office');
99
+ room.subscribe('a1', 'topic1');
100
+ room.subscribe('a1', 'topic2');
101
+ expect(room.getSubscribers('topic1')).toContain('a1');
102
+ room.removeAgent('a1');
103
+ expect(room.getSubscribers('topic1')).not.toContain('a1');
104
+ expect(room.getSubscribers('topic2')).not.toContain('a1');
105
+ });
106
+ });