opc-agent 1.1.1 → 1.1.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 (139) hide show
  1. package/CHANGELOG.md +51 -51
  2. package/CONTRIBUTING.md +75 -75
  3. package/README.md +222 -126
  4. package/README.zh-CN.md +129 -80
  5. package/dist/channels/web.js +256 -256
  6. package/dist/deploy/hermes.js +22 -22
  7. package/dist/deploy/openclaw.js +31 -31
  8. package/dist/templates/code-reviewer.js +5 -5
  9. package/dist/templates/customer-service.js +2 -2
  10. package/dist/templates/data-analyst.js +5 -5
  11. package/dist/templates/knowledge-base.js +2 -2
  12. package/dist/templates/sales-assistant.js +4 -4
  13. package/dist/templates/teacher.js +6 -6
  14. package/docs/.vitepress/config.ts +103 -103
  15. package/docs/api/cli.md +48 -48
  16. package/docs/api/oad-schema.md +64 -64
  17. package/docs/api/sdk.md +80 -80
  18. package/docs/guide/concepts.md +51 -51
  19. package/docs/guide/configuration.md +79 -79
  20. package/docs/guide/deployment.md +42 -42
  21. package/docs/guide/getting-started.md +44 -44
  22. package/docs/guide/templates.md +28 -28
  23. package/docs/guide/testing.md +84 -84
  24. package/docs/index.md +27 -27
  25. package/docs/zh/api/cli.md +54 -54
  26. package/docs/zh/api/oad-schema.md +87 -87
  27. package/docs/zh/api/sdk.md +102 -102
  28. package/docs/zh/guide/concepts.md +104 -104
  29. package/docs/zh/guide/configuration.md +135 -135
  30. package/docs/zh/guide/deployment.md +81 -81
  31. package/docs/zh/guide/getting-started.md +82 -82
  32. package/docs/zh/guide/templates.md +84 -84
  33. package/docs/zh/guide/testing.md +88 -88
  34. package/docs/zh/index.md +27 -27
  35. package/examples/customer-service-demo/README.md +90 -90
  36. package/examples/customer-service-demo/oad.yaml +107 -107
  37. package/package.json +1 -1
  38. package/src/analytics/index.ts +66 -66
  39. package/src/channels/discord.ts +192 -192
  40. package/src/channels/email.ts +177 -177
  41. package/src/channels/feishu.ts +236 -236
  42. package/src/channels/index.ts +15 -15
  43. package/src/channels/slack.ts +160 -160
  44. package/src/channels/telegram.ts +90 -90
  45. package/src/channels/voice.ts +106 -106
  46. package/src/channels/web.ts +596 -596
  47. package/src/channels/webhook.ts +199 -199
  48. package/src/channels/websocket.ts +87 -87
  49. package/src/channels/wechat.ts +149 -149
  50. package/src/core/a2a.ts +143 -143
  51. package/src/core/agent.ts +152 -152
  52. package/src/core/analytics-engine.ts +186 -186
  53. package/src/core/auth.ts +57 -57
  54. package/src/core/cache.ts +141 -141
  55. package/src/core/compose.ts +77 -77
  56. package/src/core/config.ts +14 -14
  57. package/src/core/errors.ts +148 -148
  58. package/src/core/hitl.ts +138 -138
  59. package/src/core/knowledge.ts +210 -210
  60. package/src/core/logger.ts +57 -57
  61. package/src/core/orchestrator.ts +215 -215
  62. package/src/core/performance.ts +187 -187
  63. package/src/core/rate-limiter.ts +128 -128
  64. package/src/core/room.ts +109 -109
  65. package/src/core/runtime.ts +152 -152
  66. package/src/core/sandbox.ts +101 -101
  67. package/src/core/security.ts +171 -171
  68. package/src/core/types.ts +68 -68
  69. package/src/core/versioning.ts +106 -106
  70. package/src/core/watch.ts +178 -178
  71. package/src/core/workflow.ts +235 -235
  72. package/src/deploy/hermes.ts +156 -156
  73. package/src/deploy/openclaw.ts +200 -200
  74. package/src/dtv/data.ts +29 -29
  75. package/src/dtv/trust.ts +43 -43
  76. package/src/dtv/value.ts +47 -47
  77. package/src/i18n/index.ts +216 -216
  78. package/src/index.ts +110 -110
  79. package/src/marketplace/index.ts +223 -223
  80. package/src/memory/deepbrain.ts +108 -108
  81. package/src/memory/index.ts +34 -34
  82. package/src/plugins/index.ts +208 -208
  83. package/src/providers/index.ts +183 -183
  84. package/src/schema/oad.ts +155 -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 +34 -34
  92. package/src/templates/customer-service.ts +80 -80
  93. package/src/templates/data-analyst.ts +70 -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 +31 -31
  97. package/src/templates/legal-assistant.ts +71 -71
  98. package/src/templates/sales-assistant.ts +79 -79
  99. package/src/templates/teacher.ts +79 -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/templates/Dockerfile +15 -15
  107. package/templates/code-reviewer/README.md +27 -27
  108. package/templates/code-reviewer/oad.yaml +41 -41
  109. package/templates/customer-service/README.md +22 -22
  110. package/templates/customer-service/oad.yaml +36 -36
  111. package/templates/docker-compose.yml +21 -21
  112. package/templates/knowledge-base/README.md +28 -28
  113. package/templates/knowledge-base/oad.yaml +38 -38
  114. package/templates/sales-assistant/README.md +26 -26
  115. package/templates/sales-assistant/oad.yaml +43 -43
  116. package/tests/a2a.test.ts +66 -66
  117. package/tests/agent.test.ts +72 -72
  118. package/tests/analytics.test.ts +50 -50
  119. package/tests/channel.test.ts +39 -39
  120. package/tests/e2e.test.ts +134 -134
  121. package/tests/errors.test.ts +83 -83
  122. package/tests/hitl.test.ts +71 -71
  123. package/tests/i18n.test.ts +41 -41
  124. package/tests/mcp.test.ts +54 -54
  125. package/tests/oad.test.ts +68 -68
  126. package/tests/performance.test.ts +115 -115
  127. package/tests/plugin.test.ts +74 -74
  128. package/tests/room.test.ts +106 -106
  129. package/tests/runtime.test.ts +42 -42
  130. package/tests/sandbox.test.ts +46 -46
  131. package/tests/security.test.ts +60 -60
  132. package/tests/templates.test.ts +77 -77
  133. package/tests/v070.test.ts +76 -76
  134. package/tests/versioning.test.ts +75 -75
  135. package/tests/voice.test.ts +61 -61
  136. package/tests/webhook.test.ts +29 -29
  137. package/tests/workflow.test.ts +143 -143
  138. package/tsconfig.json +19 -19
  139. package/vitest.config.ts +9 -9
@@ -1,38 +1,38 @@
1
- apiVersion: opc/v1
2
- kind: Agent
3
- metadata:
4
- name: knowledge-base
5
- version: 1.0.0
6
- description: "RAG-powered knowledge base agent using DeepBrain for semantic search"
7
- author: Deepleaper
8
- license: Apache-2.0
9
- marketplace:
10
- certified: false
11
- category: knowledge
12
- spec:
13
- provider:
14
- default: deepseek
15
- allowed: [openai, deepseek, qwen]
16
- model: deepseek-chat
17
- systemPrompt: |
18
- You are a knowledge base assistant. Answer questions using the company documents
19
- and knowledge provided to you. If you don't have enough information, say so honestly.
20
- Always cite sources when possible. Be accurate and concise.
21
- skills:
22
- - name: doc-search
23
- description: "Search company documents using semantic search"
24
- - name: doc-ingest
25
- description: "Ingest new documents into the knowledge base"
26
- channels:
27
- - type: web
28
- port: 3000
29
- memory:
30
- shortTerm: true
31
- longTerm:
32
- provider: deepbrain
33
- collection: company-knowledge
34
- dtv:
35
- trust:
36
- level: sandbox
37
- value:
38
- metrics: [queries_answered, accuracy_score, docs_indexed]
1
+ apiVersion: opc/v1
2
+ kind: Agent
3
+ metadata:
4
+ name: knowledge-base
5
+ version: 1.0.0
6
+ description: "RAG-powered knowledge base agent using DeepBrain for semantic search"
7
+ author: Deepleaper
8
+ license: Apache-2.0
9
+ marketplace:
10
+ certified: false
11
+ category: knowledge
12
+ spec:
13
+ provider:
14
+ default: deepseek
15
+ allowed: [openai, deepseek, qwen]
16
+ model: deepseek-chat
17
+ systemPrompt: |
18
+ You are a knowledge base assistant. Answer questions using the company documents
19
+ and knowledge provided to you. If you don't have enough information, say so honestly.
20
+ Always cite sources when possible. Be accurate and concise.
21
+ skills:
22
+ - name: doc-search
23
+ description: "Search company documents using semantic search"
24
+ - name: doc-ingest
25
+ description: "Ingest new documents into the knowledge base"
26
+ channels:
27
+ - type: web
28
+ port: 3000
29
+ memory:
30
+ shortTerm: true
31
+ longTerm:
32
+ provider: deepbrain
33
+ collection: company-knowledge
34
+ dtv:
35
+ trust:
36
+ level: sandbox
37
+ value:
38
+ metrics: [queries_answered, accuracy_score, docs_indexed]
@@ -1,26 +1,26 @@
1
- # Sales Assistant Template
2
-
3
- AI-powered sales assistant for product Q&A, lead capture, and appointment booking.
4
-
5
- ## Features
6
- - **Product Q&A**: Answers questions about your products/services
7
- - **Lead Capture**: Collects prospect information (name, email, company)
8
- - **Appointment Booking**: Schedules demos and meetings
9
-
10
- ## Quick Start
11
- ```bash
12
- opc init my-sales-bot --template sales-assistant
13
- cd my-sales-bot
14
- opc run
15
- ```
16
-
17
- ## Configuration
18
- Edit `oad.yaml` to customize:
19
- - System prompt with your product details
20
- - Add your product FAQ data
21
- - Configure appointment scheduling rules
22
-
23
- ## Value Metrics
24
- - `leads_captured` — Number of leads collected
25
- - `appointments_booked` — Demos/meetings scheduled
26
- - `conversion_rate` — Lead to appointment ratio
1
+ # Sales Assistant Template
2
+
3
+ AI-powered sales assistant for product Q&A, lead capture, and appointment booking.
4
+
5
+ ## Features
6
+ - **Product Q&A**: Answers questions about your products/services
7
+ - **Lead Capture**: Collects prospect information (name, email, company)
8
+ - **Appointment Booking**: Schedules demos and meetings
9
+
10
+ ## Quick Start
11
+ ```bash
12
+ opc init my-sales-bot --template sales-assistant
13
+ cd my-sales-bot
14
+ opc run
15
+ ```
16
+
17
+ ## Configuration
18
+ Edit `oad.yaml` to customize:
19
+ - System prompt with your product details
20
+ - Add your product FAQ data
21
+ - Configure appointment scheduling rules
22
+
23
+ ## Value Metrics
24
+ - `leads_captured` — Number of leads collected
25
+ - `appointments_booked` — Demos/meetings scheduled
26
+ - `conversion_rate` — Lead to appointment ratio
@@ -1,43 +1,43 @@
1
- apiVersion: opc/v1
2
- kind: Agent
3
- metadata:
4
- name: sales-assistant
5
- version: 1.0.0
6
- description: "AI sales assistant with product Q&A, lead capture, and appointment booking"
7
- author: Deepleaper
8
- license: Apache-2.0
9
- marketplace:
10
- certified: false
11
- category: sales
12
- spec:
13
- provider:
14
- default: deepseek
15
- allowed: [openai, deepseek, qwen]
16
- model: deepseek-chat
17
- systemPrompt: |
18
- You are a professional sales assistant. Your goals:
19
- 1. Answer product questions accurately and enthusiastically
20
- 2. Capture leads by collecting name, email, and company info
21
- 3. Book appointments when prospects are ready
22
- Be friendly, persuasive but not pushy. Always provide value first.
23
- skills:
24
- - name: product-qa
25
- description: "Answer product-related questions"
26
- - name: lead-capture
27
- description: "Capture prospect information"
28
- - name: appointment-booking
29
- description: "Schedule meetings and demos"
30
- channels:
31
- - type: web
32
- port: 3000
33
- - type: websocket
34
- port: 3002
35
- memory:
36
- shortTerm: true
37
- longTerm:
38
- provider: in-memory
39
- dtv:
40
- trust:
41
- level: sandbox
42
- value:
43
- metrics: [leads_captured, appointments_booked, conversion_rate]
1
+ apiVersion: opc/v1
2
+ kind: Agent
3
+ metadata:
4
+ name: sales-assistant
5
+ version: 1.0.0
6
+ description: "AI sales assistant with product Q&A, lead capture, and appointment booking"
7
+ author: Deepleaper
8
+ license: Apache-2.0
9
+ marketplace:
10
+ certified: false
11
+ category: sales
12
+ spec:
13
+ provider:
14
+ default: deepseek
15
+ allowed: [openai, deepseek, qwen]
16
+ model: deepseek-chat
17
+ systemPrompt: |
18
+ You are a professional sales assistant. Your goals:
19
+ 1. Answer product questions accurately and enthusiastically
20
+ 2. Capture leads by collecting name, email, and company info
21
+ 3. Book appointments when prospects are ready
22
+ Be friendly, persuasive but not pushy. Always provide value first.
23
+ skills:
24
+ - name: product-qa
25
+ description: "Answer product-related questions"
26
+ - name: lead-capture
27
+ description: "Capture prospect information"
28
+ - name: appointment-booking
29
+ description: "Schedule meetings and demos"
30
+ channels:
31
+ - type: web
32
+ port: 3000
33
+ - type: websocket
34
+ port: 3002
35
+ memory:
36
+ shortTerm: true
37
+ longTerm:
38
+ provider: in-memory
39
+ dtv:
40
+ trust:
41
+ level: sandbox
42
+ value:
43
+ metrics: [leads_captured, appointments_booked, conversion_rate]
package/tests/a2a.test.ts CHANGED
@@ -1,66 +1,66 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { AgentRegistry } from '../src/core/a2a';
3
- import { BaseAgent } from '../src/core/agent';
4
- import { InMemoryStore } from '../src/memory';
5
-
6
- function createTestAgent(name: string): BaseAgent {
7
- const agent = new BaseAgent({ name, model: 'test', systemPrompt: `I am ${name}` }, new InMemoryStore());
8
- return agent;
9
- }
10
-
11
- describe('AgentRegistry (A2A)', () => {
12
- let registry: AgentRegistry;
13
-
14
- beforeEach(() => {
15
- registry = new AgentRegistry();
16
- });
17
-
18
- it('should register and discover agents', () => {
19
- const agent = createTestAgent('agent-1');
20
- registry.register(agent, [{ name: 'summarize', description: 'Summarize text' }]);
21
-
22
- const all = registry.discover();
23
- expect(all).toHaveLength(1);
24
- expect(all[0].agentName).toBe('agent-1');
25
- });
26
-
27
- it('should discover by capability', () => {
28
- const a1 = createTestAgent('a1');
29
- const a2 = createTestAgent('a2');
30
- registry.register(a1, [{ name: 'summarize', description: 'Summarize' }]);
31
- registry.register(a2, [{ name: 'translate', description: 'Translate' }]);
32
-
33
- const found = registry.discover('translate');
34
- expect(found).toHaveLength(1);
35
- expect(found[0].agentName).toBe('a2');
36
- });
37
-
38
- it('should unregister agents', () => {
39
- const agent = createTestAgent('temp');
40
- registry.register(agent, []);
41
- registry.unregister('temp');
42
- expect(registry.discover()).toHaveLength(0);
43
- });
44
-
45
- it('should handle request to unknown agent', async () => {
46
- const response = await registry.call('a1', 'unknown', 'test', 'hello');
47
- expect(response.status).toBe('error');
48
- });
49
-
50
- it('should send A2A request and get response', async () => {
51
- const agent = createTestAgent('responder');
52
- await agent.init();
53
- registry.register(agent, [{ name: 'chat', description: 'Chat' }]);
54
-
55
- const response = await registry.call('caller', 'responder', 'chat', 'hello');
56
- expect(response.status).toBe('success');
57
- expect(response.payload).toBeDefined();
58
- });
59
-
60
- it('should get agent by name', () => {
61
- const agent = createTestAgent('finder');
62
- registry.register(agent, []);
63
- expect(registry.getAgent('finder')).toBeDefined();
64
- expect(registry.getAgent('none')).toBeUndefined();
65
- });
66
- });
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { AgentRegistry } from '../src/core/a2a';
3
+ import { BaseAgent } from '../src/core/agent';
4
+ import { InMemoryStore } from '../src/memory';
5
+
6
+ function createTestAgent(name: string): BaseAgent {
7
+ const agent = new BaseAgent({ name, model: 'test', systemPrompt: `I am ${name}` }, new InMemoryStore());
8
+ return agent;
9
+ }
10
+
11
+ describe('AgentRegistry (A2A)', () => {
12
+ let registry: AgentRegistry;
13
+
14
+ beforeEach(() => {
15
+ registry = new AgentRegistry();
16
+ });
17
+
18
+ it('should register and discover agents', () => {
19
+ const agent = createTestAgent('agent-1');
20
+ registry.register(agent, [{ name: 'summarize', description: 'Summarize text' }]);
21
+
22
+ const all = registry.discover();
23
+ expect(all).toHaveLength(1);
24
+ expect(all[0].agentName).toBe('agent-1');
25
+ });
26
+
27
+ it('should discover by capability', () => {
28
+ const a1 = createTestAgent('a1');
29
+ const a2 = createTestAgent('a2');
30
+ registry.register(a1, [{ name: 'summarize', description: 'Summarize' }]);
31
+ registry.register(a2, [{ name: 'translate', description: 'Translate' }]);
32
+
33
+ const found = registry.discover('translate');
34
+ expect(found).toHaveLength(1);
35
+ expect(found[0].agentName).toBe('a2');
36
+ });
37
+
38
+ it('should unregister agents', () => {
39
+ const agent = createTestAgent('temp');
40
+ registry.register(agent, []);
41
+ registry.unregister('temp');
42
+ expect(registry.discover()).toHaveLength(0);
43
+ });
44
+
45
+ it('should handle request to unknown agent', async () => {
46
+ const response = await registry.call('a1', 'unknown', 'test', 'hello');
47
+ expect(response.status).toBe('error');
48
+ });
49
+
50
+ it('should send A2A request and get response', async () => {
51
+ const agent = createTestAgent('responder');
52
+ await agent.init();
53
+ registry.register(agent, [{ name: 'chat', description: 'Chat' }]);
54
+
55
+ const response = await registry.call('caller', 'responder', 'chat', 'hello');
56
+ expect(response.status).toBe('success');
57
+ expect(response.payload).toBeDefined();
58
+ });
59
+
60
+ it('should get agent by name', () => {
61
+ const agent = createTestAgent('finder');
62
+ registry.register(agent, []);
63
+ expect(registry.getAgent('finder')).toBeDefined();
64
+ expect(registry.getAgent('none')).toBeUndefined();
65
+ });
66
+ });
@@ -1,72 +1,72 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { BaseAgent } from '../src/core/agent';
3
-
4
- describe('BaseAgent', () => {
5
- it('should start in init state', () => {
6
- const agent = new BaseAgent({ name: 'test' });
7
- expect(agent.state).toBe('init');
8
- expect(agent.name).toBe('test');
9
- });
10
-
11
- it('should transition through lifecycle', async () => {
12
- const agent = new BaseAgent({ name: 'test' });
13
- const states: string[] = [];
14
- agent.on('state:change', (_from, to) => states.push(to));
15
-
16
- await agent.init();
17
- expect(agent.state).toBe('ready');
18
-
19
- await agent.start();
20
- expect(agent.state).toBe('running');
21
-
22
- await agent.stop();
23
- expect(agent.state).toBe('stopped');
24
-
25
- expect(states).toEqual(['ready', 'running', 'stopped']);
26
- });
27
-
28
- it('should not start if not ready', async () => {
29
- const agent = new BaseAgent({ name: 'test' });
30
- await expect(agent.start()).rejects.toThrow('Cannot start agent in state: init');
31
- });
32
-
33
- it('should handle messages with stub provider', async () => {
34
- const agent = new BaseAgent({ name: 'test', systemPrompt: 'Be helpful' });
35
- await agent.init();
36
-
37
- const response = await agent.handleMessage({
38
- id: 'msg_1',
39
- role: 'user',
40
- content: 'Hello',
41
- timestamp: Date.now(),
42
- });
43
-
44
- expect(response.role).toBe('assistant');
45
- expect(response.content).toContain('Hello');
46
- });
47
-
48
- it('should use skills before LLM fallback', async () => {
49
- const agent = new BaseAgent({ name: 'test' });
50
- await agent.init();
51
-
52
- agent.registerSkill({
53
- name: 'greeter',
54
- description: 'Greets users',
55
- execute: async (_ctx, msg) => {
56
- if (msg.content.toLowerCase().includes('hello')) {
57
- return { handled: true, response: 'Hi there!', confidence: 1.0 };
58
- }
59
- return { handled: false, confidence: 0 };
60
- },
61
- });
62
-
63
- const response = await agent.handleMessage({
64
- id: 'msg_1',
65
- role: 'user',
66
- content: 'Hello!',
67
- timestamp: Date.now(),
68
- });
69
-
70
- expect(response.content).toBe('Hi there!');
71
- });
72
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { BaseAgent } from '../src/core/agent';
3
+
4
+ describe('BaseAgent', () => {
5
+ it('should start in init state', () => {
6
+ const agent = new BaseAgent({ name: 'test' });
7
+ expect(agent.state).toBe('init');
8
+ expect(agent.name).toBe('test');
9
+ });
10
+
11
+ it('should transition through lifecycle', async () => {
12
+ const agent = new BaseAgent({ name: 'test' });
13
+ const states: string[] = [];
14
+ agent.on('state:change', (_from, to) => states.push(to));
15
+
16
+ await agent.init();
17
+ expect(agent.state).toBe('ready');
18
+
19
+ await agent.start();
20
+ expect(agent.state).toBe('running');
21
+
22
+ await agent.stop();
23
+ expect(agent.state).toBe('stopped');
24
+
25
+ expect(states).toEqual(['ready', 'running', 'stopped']);
26
+ });
27
+
28
+ it('should not start if not ready', async () => {
29
+ const agent = new BaseAgent({ name: 'test' });
30
+ await expect(agent.start()).rejects.toThrow('Cannot start agent in state: init');
31
+ });
32
+
33
+ it('should handle messages with stub provider', async () => {
34
+ const agent = new BaseAgent({ name: 'test', systemPrompt: 'Be helpful' });
35
+ await agent.init();
36
+
37
+ const response = await agent.handleMessage({
38
+ id: 'msg_1',
39
+ role: 'user',
40
+ content: 'Hello',
41
+ timestamp: Date.now(),
42
+ });
43
+
44
+ expect(response.role).toBe('assistant');
45
+ expect(response.content).toContain('Hello');
46
+ });
47
+
48
+ it('should use skills before LLM fallback', async () => {
49
+ const agent = new BaseAgent({ name: 'test' });
50
+ await agent.init();
51
+
52
+ agent.registerSkill({
53
+ name: 'greeter',
54
+ description: 'Greets users',
55
+ execute: async (_ctx, msg) => {
56
+ if (msg.content.toLowerCase().includes('hello')) {
57
+ return { handled: true, response: 'Hi there!', confidence: 1.0 };
58
+ }
59
+ return { handled: false, confidence: 0 };
60
+ },
61
+ });
62
+
63
+ const response = await agent.handleMessage({
64
+ id: 'msg_1',
65
+ role: 'user',
66
+ content: 'Hello!',
67
+ timestamp: Date.now(),
68
+ });
69
+
70
+ expect(response.content).toBe('Hi there!');
71
+ });
72
+ });
@@ -1,50 +1,50 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { Analytics } from '../src/analytics';
3
-
4
- describe('Analytics', () => {
5
- it('should track messages', () => {
6
- const analytics = new Analytics();
7
- analytics.recordMessage(100);
8
- analytics.recordMessage(200);
9
- const snap = analytics.getSnapshot();
10
- expect(snap.messagesProcessed).toBe(2);
11
- expect(snap.avgResponseTimeMs).toBe(150);
12
- });
13
-
14
- it('should track skill usage', () => {
15
- const analytics = new Analytics();
16
- analytics.recordSkillUsage('faq');
17
- analytics.recordSkillUsage('faq');
18
- analytics.recordSkillUsage('handoff');
19
- const snap = analytics.getSnapshot();
20
- expect(snap.skillUsage['faq']).toBe(2);
21
- expect(snap.skillUsage['handoff']).toBe(1);
22
- });
23
-
24
- it('should track errors', () => {
25
- const analytics = new Analytics();
26
- analytics.recordError();
27
- analytics.recordError();
28
- expect(analytics.getSnapshot().errorCount).toBe(2);
29
- });
30
-
31
- it('should track token usage', () => {
32
- const analytics = new Analytics();
33
- analytics.recordTokens(100, 50);
34
- analytics.recordTokens(200, 100);
35
- const snap = analytics.getSnapshot();
36
- expect(snap.tokenUsage.input).toBe(300);
37
- expect(snap.tokenUsage.output).toBe(150);
38
- expect(snap.tokenUsage.total).toBe(450);
39
- });
40
-
41
- it('should reset analytics', () => {
42
- const analytics = new Analytics();
43
- analytics.recordMessage(100);
44
- analytics.recordError();
45
- analytics.reset();
46
- const snap = analytics.getSnapshot();
47
- expect(snap.messagesProcessed).toBe(0);
48
- expect(snap.errorCount).toBe(0);
49
- });
50
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Analytics } from '../src/analytics';
3
+
4
+ describe('Analytics', () => {
5
+ it('should track messages', () => {
6
+ const analytics = new Analytics();
7
+ analytics.recordMessage(100);
8
+ analytics.recordMessage(200);
9
+ const snap = analytics.getSnapshot();
10
+ expect(snap.messagesProcessed).toBe(2);
11
+ expect(snap.avgResponseTimeMs).toBe(150);
12
+ });
13
+
14
+ it('should track skill usage', () => {
15
+ const analytics = new Analytics();
16
+ analytics.recordSkillUsage('faq');
17
+ analytics.recordSkillUsage('faq');
18
+ analytics.recordSkillUsage('handoff');
19
+ const snap = analytics.getSnapshot();
20
+ expect(snap.skillUsage['faq']).toBe(2);
21
+ expect(snap.skillUsage['handoff']).toBe(1);
22
+ });
23
+
24
+ it('should track errors', () => {
25
+ const analytics = new Analytics();
26
+ analytics.recordError();
27
+ analytics.recordError();
28
+ expect(analytics.getSnapshot().errorCount).toBe(2);
29
+ });
30
+
31
+ it('should track token usage', () => {
32
+ const analytics = new Analytics();
33
+ analytics.recordTokens(100, 50);
34
+ analytics.recordTokens(200, 100);
35
+ const snap = analytics.getSnapshot();
36
+ expect(snap.tokenUsage.input).toBe(300);
37
+ expect(snap.tokenUsage.output).toBe(150);
38
+ expect(snap.tokenUsage.total).toBe(450);
39
+ });
40
+
41
+ it('should reset analytics', () => {
42
+ const analytics = new Analytics();
43
+ analytics.recordMessage(100);
44
+ analytics.recordError();
45
+ analytics.reset();
46
+ const snap = analytics.getSnapshot();
47
+ expect(snap.messagesProcessed).toBe(0);
48
+ expect(snap.errorCount).toBe(0);
49
+ });
50
+ });