@creatoria/miniapp-mcp 0.1.3 → 0.2.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.
- package/README.md +14 -3
- package/dist/app/cli/index.d.ts +6 -0
- package/dist/app/cli/index.d.ts.map +1 -0
- package/dist/app/cli/index.js +6 -0
- package/dist/app/cli/index.js.map +1 -0
- package/dist/app/index.d.ts +6 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +6 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/server/index.d.ts +7 -0
- package/dist/app/server/index.d.ts.map +1 -0
- package/dist/app/server/index.js +6 -0
- package/dist/app/server/index.js.map +1 -0
- package/dist/capabilities/assert/index.d.ts +5 -0
- package/dist/capabilities/assert/index.d.ts.map +1 -0
- package/dist/capabilities/assert/index.js +5 -0
- package/dist/capabilities/assert/index.js.map +1 -0
- package/dist/capabilities/automator/index.d.ts +6 -0
- package/dist/capabilities/automator/index.d.ts.map +1 -0
- package/dist/capabilities/automator/index.js +6 -0
- package/dist/capabilities/automator/index.js.map +1 -0
- package/dist/capabilities/automator/schemas/close.d.ts +5 -0
- package/dist/capabilities/automator/schemas/close.d.ts.map +1 -0
- package/dist/capabilities/automator/schemas/close.js +11 -0
- package/dist/capabilities/automator/schemas/close.js.map +1 -0
- package/dist/capabilities/automator/schemas/connect.d.ts +11 -0
- package/dist/capabilities/automator/schemas/connect.d.ts.map +1 -0
- package/dist/capabilities/automator/schemas/connect.js +19 -0
- package/dist/capabilities/automator/schemas/connect.js.map +1 -0
- package/dist/capabilities/automator/schemas/disconnect.d.ts +5 -0
- package/dist/capabilities/automator/schemas/disconnect.d.ts.map +1 -0
- package/dist/capabilities/automator/schemas/disconnect.js +11 -0
- package/dist/capabilities/automator/schemas/disconnect.js.map +1 -0
- package/dist/capabilities/automator/schemas/index.d.ts +4 -0
- package/dist/capabilities/automator/schemas/index.d.ts.map +1 -0
- package/dist/capabilities/automator/schemas/index.js +12 -0
- package/dist/capabilities/automator/schemas/index.js.map +1 -0
- package/dist/capabilities/automator/schemas/launch.d.ts +17 -0
- package/dist/capabilities/automator/schemas/launch.d.ts.map +1 -0
- package/dist/capabilities/automator/schemas/launch.js +26 -0
- package/dist/capabilities/automator/schemas/launch.js.map +1 -0
- package/dist/capabilities/element/index.d.ts +5 -0
- package/dist/capabilities/element/index.d.ts.map +1 -0
- package/dist/capabilities/element/index.js +5 -0
- package/dist/capabilities/element/index.js.map +1 -0
- package/dist/capabilities/index.d.ts +15 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +14 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/miniprogram/index.d.ts +5 -0
- package/dist/capabilities/miniprogram/index.d.ts.map +1 -0
- package/dist/capabilities/miniprogram/index.js +5 -0
- package/dist/capabilities/miniprogram/index.js.map +1 -0
- package/dist/capabilities/network/index.d.ts +5 -0
- package/dist/capabilities/network/index.d.ts.map +1 -0
- package/dist/capabilities/network/index.js +5 -0
- package/dist/capabilities/network/index.js.map +1 -0
- package/dist/capabilities/page/index.d.ts +5 -0
- package/dist/capabilities/page/index.d.ts.map +1 -0
- package/dist/capabilities/page/index.js +5 -0
- package/dist/capabilities/page/index.js.map +1 -0
- package/dist/capabilities/record/index.d.ts +5 -0
- package/dist/capabilities/record/index.d.ts.map +1 -0
- package/dist/capabilities/record/index.js +5 -0
- package/dist/capabilities/record/index.js.map +1 -0
- package/dist/capabilities/schema-registry.d.ts +4 -0
- package/dist/capabilities/schema-registry.d.ts.map +1 -0
- package/dist/capabilities/schema-registry.js +18 -0
- package/dist/capabilities/schema-registry.js.map +1 -0
- package/dist/capabilities/schema-types.d.ts +22 -0
- package/dist/capabilities/schema-types.d.ts.map +1 -0
- package/dist/capabilities/schema-types.js +2 -0
- package/dist/capabilities/schema-types.js.map +1 -0
- package/dist/capabilities/snapshot/index.d.ts +5 -0
- package/dist/capabilities/snapshot/index.d.ts.map +1 -0
- package/dist/capabilities/snapshot/index.js +5 -0
- package/dist/capabilities/snapshot/index.js.map +1 -0
- package/dist/config/loader.js +1 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/core/element-ref.d.ts +1 -43
- package/dist/core/element-ref.d.ts.map +1 -1
- package/dist/core/element-ref.js +1 -212
- package/dist/core/element-ref.js.map +1 -1
- package/dist/core/logger.d.ts +1 -54
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +1 -377
- package/dist/core/logger.js.map +1 -1
- package/dist/core/output.d.ts +1 -20
- package/dist/core/output.d.ts.map +1 -1
- package/dist/core/output.js +1 -55
- package/dist/core/output.js.map +1 -1
- package/dist/core/report-generator.d.ts +1 -23
- package/dist/core/report-generator.d.ts.map +1 -1
- package/dist/core/report-generator.js +1 -211
- package/dist/core/report-generator.js.map +1 -1
- package/dist/core/session.d.ts +2 -82
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +2 -305
- package/dist/core/session.js.map +1 -1
- package/dist/core/timeout.d.ts +1 -48
- package/dist/core/timeout.d.ts.map +1 -1
- package/dist/core/timeout.js +1 -66
- package/dist/core/timeout.js.map +1 -1
- package/dist/core/tool-logger.d.ts +1 -82
- package/dist/core/tool-logger.d.ts.map +1 -1
- package/dist/core/tool-logger.js +1 -452
- package/dist/core/tool-logger.js.map +1 -1
- package/dist/core/validation.d.ts +1 -38
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +1 -92
- package/dist/core/validation.js.map +1 -1
- package/dist/runtime/element/element-ref.d.ts +44 -0
- package/dist/runtime/element/element-ref.d.ts.map +1 -0
- package/dist/runtime/element/element-ref.js +214 -0
- package/dist/runtime/element/element-ref.js.map +1 -0
- package/dist/runtime/element/index.d.ts +2 -0
- package/dist/runtime/element/index.d.ts.map +1 -0
- package/dist/runtime/element/index.js +2 -0
- package/dist/runtime/element/index.js.map +1 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/logging/index.d.ts +3 -0
- package/dist/runtime/logging/index.d.ts.map +1 -0
- package/dist/runtime/logging/index.js +3 -0
- package/dist/runtime/logging/index.js.map +1 -0
- package/dist/runtime/logging/logger.d.ts +55 -0
- package/dist/runtime/logging/logger.d.ts.map +1 -0
- package/dist/runtime/logging/logger.js +379 -0
- package/dist/runtime/logging/logger.js.map +1 -0
- package/dist/runtime/logging/tool-logger.d.ts +83 -0
- package/dist/runtime/logging/tool-logger.d.ts.map +1 -0
- package/dist/runtime/logging/tool-logger.js +454 -0
- package/dist/runtime/logging/tool-logger.js.map +1 -0
- package/dist/runtime/outputs/index.d.ts +3 -0
- package/dist/runtime/outputs/index.d.ts.map +1 -0
- package/dist/runtime/outputs/index.js +3 -0
- package/dist/runtime/outputs/index.js.map +1 -0
- package/dist/runtime/outputs/output-manager.d.ts +12 -0
- package/dist/runtime/outputs/output-manager.d.ts.map +1 -0
- package/dist/runtime/outputs/output-manager.js +39 -0
- package/dist/runtime/outputs/output-manager.js.map +1 -0
- package/dist/runtime/outputs/report-generator.d.ts +5 -0
- package/dist/runtime/outputs/report-generator.d.ts.map +1 -0
- package/dist/runtime/outputs/report-generator.js +175 -0
- package/dist/runtime/outputs/report-generator.js.map +1 -0
- package/dist/runtime/session/index.d.ts +3 -0
- package/dist/runtime/session/index.d.ts.map +1 -0
- package/dist/runtime/session/index.js +3 -0
- package/dist/runtime/session/index.js.map +1 -0
- package/dist/runtime/session/store.d.ts +28 -0
- package/dist/runtime/session/store.d.ts.map +1 -0
- package/dist/runtime/session/store.js +154 -0
- package/dist/runtime/session/store.js.map +1 -0
- package/dist/runtime/session/utils/cleanup.d.ts +3 -0
- package/dist/runtime/session/utils/cleanup.d.ts.map +1 -0
- package/dist/runtime/session/utils/cleanup.js +78 -0
- package/dist/runtime/session/utils/cleanup.js.map +1 -0
- package/dist/runtime/timeout/index.d.ts +2 -0
- package/dist/runtime/timeout/index.d.ts.map +1 -0
- package/dist/runtime/timeout/index.js +2 -0
- package/dist/runtime/timeout/index.js.map +1 -0
- package/dist/runtime/timeout/timeout.d.ts +49 -0
- package/dist/runtime/timeout/timeout.d.ts.map +1 -0
- package/dist/runtime/timeout/timeout.js +67 -0
- package/dist/runtime/timeout/timeout.js.map +1 -0
- package/dist/runtime/validation/index.d.ts +2 -0
- package/dist/runtime/validation/index.d.ts.map +1 -0
- package/dist/runtime/validation/index.js +2 -0
- package/dist/runtime/validation/index.js.map +1 -0
- package/dist/runtime/validation/validation.d.ts +39 -0
- package/dist/runtime/validation/validation.d.ts.map +1 -0
- package/dist/runtime/validation/validation.js +93 -0
- package/dist/runtime/validation/validation.js.map +1 -0
- package/dist/schemas/automator/miniprogram_close.json +12 -0
- package/dist/schemas/automator/miniprogram_connect.json +19 -0
- package/dist/schemas/automator/miniprogram_disconnect.json +12 -0
- package/dist/schemas/automator/miniprogram_launch.json +30 -0
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/miniprogram.d.ts +0 -1
- package/dist/tools/miniprogram.d.ts.map +1 -1
- package/dist/tools/miniprogram.js +17 -29
- package/dist/tools/miniprogram.js.map +1 -1
- package/dist/tools/page.js +2 -2
- package/dist/tools/page.js.map +1 -1
- package/docs/directory-structure-and-code-style-best-practices.md +91 -0
- package/docs/migration/README.md +34 -0
- package/docs/migration/TC-ALIGN-01-notes.md +35 -0
- package/docs/migration/runtime-skeleton.md +50 -0
- package/docs/migration/tool-schema-strategy.md +75 -0
- package/docs//345/256/214/346/225/264/345/256/236/347/216/260/346/226/271/346/241/210.md +14 -14
- package/docs//347/254/254/344/270/200/347/211/210/346/234/254/346/226/271/346/241/210.md +7 -7
- package/package.json +4 -2
- package/docs/SIMPLE_USAGE.md +0 -210
- package/docs/architecture.E-Docs.md +0 -1359
- package/docs/architecture.F1.md +0 -720
- package/docs/architecture.F2.md +0 -871
- package/docs/architecture.F3.md +0 -905
- package/docs/architecture.md +0 -90
- package/docs/charter.A1.align.yaml +0 -170
- package/docs/charter.A2.align.yaml +0 -199
- package/docs/charter.A3.align.yaml +0 -242
- package/docs/charter.A4.align.yaml +0 -227
- package/docs/charter.B1.align.yaml +0 -179
- package/docs/charter.B2.align.yaml +0 -200
- package/docs/charter.B3.align.yaml +0 -200
- package/docs/charter.B4.align.yaml +0 -188
- package/docs/charter.C1.align.yaml +0 -190
- package/docs/charter.C2.align.yaml +0 -202
- package/docs/charter.C3.align.yaml +0 -211
- package/docs/charter.C4.align.yaml +0 -263
- package/docs/charter.C5.align.yaml +0 -220
- package/docs/charter.D1.align.yaml +0 -190
- package/docs/charter.D2.align.yaml +0 -234
- package/docs/charter.D3.align.yaml +0 -206
- package/docs/charter.E-Docs.align.yaml +0 -294
- package/docs/charter.F1.align.yaml +0 -193
- package/docs/charter.F2.align.yaml +0 -248
- package/docs/charter.F3.align.yaml +0 -287
- package/docs/charter.G.align.yaml +0 -174
- package/docs/charter.align.yaml +0 -111
- package/docs/maintenance.md +0 -682
- package/docs/playwright-mcp/350/260/203/347/240/224.md +0 -53
- package/docs/setup-guide.md +0 -775
- package/docs/tasks.A1.atomize.md +0 -296
- package/docs/tasks.A2.atomize.md +0 -408
- package/docs/tasks.A3.atomize.md +0 -564
- package/docs/tasks.A4.atomize.md +0 -496
- package/docs/tasks.B1.atomize.md +0 -352
- package/docs/tasks.B2.atomize.md +0 -561
- package/docs/tasks.B3.atomize.md +0 -508
- package/docs/tasks.B4.atomize.md +0 -504
- package/docs/tasks.C1.atomize.md +0 -540
- package/docs/tasks.C2.atomize.md +0 -665
- package/docs/tasks.C3.atomize.md +0 -745
- package/docs/tasks.C4.atomize.md +0 -908
- package/docs/tasks.C5.atomize.md +0 -755
- package/docs/tasks.D1.atomize.md +0 -547
- package/docs/tasks.D2.atomize.md +0 -619
- package/docs/tasks.D3.atomize.md +0 -790
- package/docs/tasks.E-Docs.atomize.md +0 -1204
- package/docs/tasks.atomize.md +0 -189
package/docs/architecture.F3.md
DELETED
|
@@ -1,905 +0,0 @@
|
|
|
1
|
-
# Architecture: F3 - 会话报告生成
|
|
2
|
-
|
|
3
|
-
## 文档信息
|
|
4
|
-
- **项目**: creatoria-miniapp-mcp
|
|
5
|
-
- **阶段**: F - 可观测性与产物输出
|
|
6
|
-
- **任务**: F3 - 会话报告生成(JSON/Markdown 汇总)
|
|
7
|
-
- **作者**: ClaudeCode
|
|
8
|
-
- **日期**: 2025-10-03
|
|
9
|
-
- **版本**: 1.0
|
|
10
|
-
|
|
11
|
-
## 目录
|
|
12
|
-
1. [系统概述](#1-系统概述)
|
|
13
|
-
2. [架构设计](#2-架构设计)
|
|
14
|
-
3. [详细设计](#3-详细设计)
|
|
15
|
-
4. [接口设计](#4-接口设计)
|
|
16
|
-
5. [数据模型](#5-数据模型)
|
|
17
|
-
6. [错误处理](#6-错误处理)
|
|
18
|
-
7. [性能考量](#7-性能考量)
|
|
19
|
-
8. [安全性](#8-安全性)
|
|
20
|
-
9. [测试策略](#9-测试策略)
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## 1. 系统概述
|
|
25
|
-
|
|
26
|
-
### 1.1 背景
|
|
27
|
-
自动化测试执行后,开发者需要查看执行结果、成功率、失败原因等信息。F3 任务实现会话级别的报告生成,将所有工具调用汇总为结构化报告(JSON)和可读报告(Markdown),便于分析和分享。
|
|
28
|
-
|
|
29
|
-
### 1.2 目标
|
|
30
|
-
- **会话汇总**:自动收集所有工具调用记录
|
|
31
|
-
- **双格式输出**:JSON(机器可读)+ Markdown(人类可读)
|
|
32
|
-
- **失败追踪**:关联 F2 快照路径
|
|
33
|
-
- **性能分析**:提供耗时统计和性能指标
|
|
34
|
-
|
|
35
|
-
### 1.3 关键约束
|
|
36
|
-
- 依赖 F1 日志系统(ToolLogger)
|
|
37
|
-
- 依赖 F2 快照路径格式
|
|
38
|
-
- 默认禁用(显式启用)
|
|
39
|
-
- Fire-and-forget 模式(不阻塞关闭)
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 2. 架构设计
|
|
44
|
-
|
|
45
|
-
### 2.1 C4 模型
|
|
46
|
-
|
|
47
|
-
#### Level 1: 系统上下文图
|
|
48
|
-
```
|
|
49
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
50
|
-
│ │
|
|
51
|
-
│ MCP Client (Claude) │
|
|
52
|
-
│ │
|
|
53
|
-
└────────────────────────┬────────────────────────────────────────┘
|
|
54
|
-
│ MCP Protocol
|
|
55
|
-
│ (stdio transport)
|
|
56
|
-
v
|
|
57
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
58
|
-
│ │
|
|
59
|
-
│ MCP Server (miniapp-mcp) │
|
|
60
|
-
│ │
|
|
61
|
-
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
62
|
-
│ │ Session Report Generator (F3) │ │
|
|
63
|
-
│ │ - Collects tool call records │ │
|
|
64
|
-
│ │ - Generates JSON/Markdown reports on session close │ │
|
|
65
|
-
│ │ - Links to F2 failure snapshots │ │
|
|
66
|
-
│ └─────────────────────────────────────────────────────────┘ │
|
|
67
|
-
│ │ │
|
|
68
|
-
└─────────────────────────┼────────────────────────────────────────┘
|
|
69
|
-
│
|
|
70
|
-
v
|
|
71
|
-
┌───────────────────────┐
|
|
72
|
-
│ File System │
|
|
73
|
-
│ .mcp-artifacts/ │
|
|
74
|
-
│ report.json │
|
|
75
|
-
│ report.md │
|
|
76
|
-
└───────────────────────┘
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
#### Level 2: 容器图
|
|
80
|
-
```
|
|
81
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
82
|
-
│ MCP Server Process │
|
|
83
|
-
│ │
|
|
84
|
-
│ ┌────────────────┐ ┌────────────────┐ ┌─────────────────┐ │
|
|
85
|
-
│ │ ToolLogger │────>│ ReportCollector│────>│ ReportGenerator │ │
|
|
86
|
-
│ │ (F1) │ │ │ │ │ │
|
|
87
|
-
│ │ - wrap() │ │ - record() │ │ - generateJSON()│ │
|
|
88
|
-
│ │ - log calls │ │ - aggregate() │ │ - generateMD() │ │
|
|
89
|
-
│ └────────────────┘ └────────────────┘ └─────────────────┘ │
|
|
90
|
-
│ │ │ │ │
|
|
91
|
-
│ │ │ v │
|
|
92
|
-
│ v v ┌─────────────────┐ │
|
|
93
|
-
│ ┌────────────────┐ ┌────────────────┐ │ OutputManager │ │
|
|
94
|
-
│ │ SessionState │ │ SessionState │ │ │ │
|
|
95
|
-
│ │ - reportData │<────│ - reportData │ │ - writeFile() │ │
|
|
96
|
-
│ │ .toolCalls[] │ │ .toolCalls[] │ └─────────────────┘ │
|
|
97
|
-
│ └────────────────┘ └────────────────┘ │
|
|
98
|
-
└──────────────────────────────────────────────────────────────────────┘
|
|
99
|
-
│
|
|
100
|
-
v
|
|
101
|
-
┌─────────────────────────────┐
|
|
102
|
-
│ Artifacts Directory │
|
|
103
|
-
│ │
|
|
104
|
-
│ {sessionId}/ │
|
|
105
|
-
│ ├─ report.json │
|
|
106
|
-
│ ├─ report.md │
|
|
107
|
-
│ └─ failures/ │
|
|
108
|
-
└─────────────────────────────┘
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
#### Level 3: 组件图
|
|
112
|
-
```
|
|
113
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
114
|
-
│ ToolLogger (F1) │
|
|
115
|
-
│ │
|
|
116
|
-
│ wrap(toolName, handler) { │
|
|
117
|
-
│ const startTime = Date.now() │
|
|
118
|
-
│ │
|
|
119
|
-
│ try { │
|
|
120
|
-
│ const result = await handler(session, args) │
|
|
121
|
-
│ const duration = Date.now() - startTime │
|
|
122
|
-
│ │
|
|
123
|
-
│ // F3: Record successful call │
|
|
124
|
-
│ if (session.reportData) { │
|
|
125
|
-
│ session.reportData.toolCalls.push({ │
|
|
126
|
-
│ timestamp, toolName, duration, success: true, result │
|
|
127
|
-
│ }) │
|
|
128
|
-
│ } │
|
|
129
|
-
│ │
|
|
130
|
-
│ return result │
|
|
131
|
-
│ } catch (error) { │
|
|
132
|
-
│ const duration = Date.now() - startTime │
|
|
133
|
-
│ │
|
|
134
|
-
│ // F3: Record failed call │
|
|
135
|
-
│ if (session.reportData) { │
|
|
136
|
-
│ session.reportData.toolCalls.push({ │
|
|
137
|
-
│ timestamp, toolName, duration, success: false, │
|
|
138
|
-
│ error: { message, snapshotPath } │
|
|
139
|
-
│ }) │
|
|
140
|
-
│ } │
|
|
141
|
-
│ │
|
|
142
|
-
│ throw error │
|
|
143
|
-
│ } │
|
|
144
|
-
│ } │
|
|
145
|
-
└──────────────────────────────────────────────────────────────────────┘
|
|
146
|
-
|
|
147
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
148
|
-
│ SessionStore.dispose() │
|
|
149
|
-
│ │
|
|
150
|
-
│ async dispose() { │
|
|
151
|
-
│ // Close all sessions │
|
|
152
|
-
│ for (const sessionId of this.sessions.keys()) { │
|
|
153
|
-
│ const session = this.sessions.get(sessionId) │
|
|
154
|
-
│ │
|
|
155
|
-
│ // F3: Generate report before cleanup │
|
|
156
|
-
│ if (session.reportData && config.enableSessionReport) { │
|
|
157
|
-
│ void generateSessionReport(session).catch(err => { │
|
|
158
|
-
│ logger.warn('Report generation failed', err) │
|
|
159
|
-
│ }) │
|
|
160
|
-
│ } │
|
|
161
|
-
│ │
|
|
162
|
-
│ await this.delete(sessionId) │
|
|
163
|
-
│ } │
|
|
164
|
-
│ } │
|
|
165
|
-
└──────────────────────────────────────────────────────────────────────┘
|
|
166
|
-
|
|
167
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
168
|
-
│ ReportGenerator │
|
|
169
|
-
│ │
|
|
170
|
-
│ async generateSessionReport(session: SessionState) { │
|
|
171
|
-
│ const { reportData, sessionId, outputManager } = session │
|
|
172
|
-
│ │
|
|
173
|
-
│ // 1. Calculate summary statistics │
|
|
174
|
-
│ const summary = calculateSummary(reportData.toolCalls) │
|
|
175
|
-
│ │
|
|
176
|
-
│ // 2. Extract failures │
|
|
177
|
-
│ const failures = reportData.toolCalls │
|
|
178
|
-
│ .filter(call => !call.success) │
|
|
179
|
-
│ .map(call => ({ │
|
|
180
|
-
│ toolName: call.toolName, │
|
|
181
|
-
│ timestamp: call.timestamp, │
|
|
182
|
-
│ error: call.error.message, │
|
|
183
|
-
│ snapshotPath: call.error.snapshotPath │
|
|
184
|
-
│ })) │
|
|
185
|
-
│ │
|
|
186
|
-
│ // 3. Generate JSON report │
|
|
187
|
-
│ const jsonReport = { │
|
|
188
|
-
│ sessionId, │
|
|
189
|
-
│ startTime: reportData.startTime, │
|
|
190
|
-
│ endTime: reportData.endTime, │
|
|
191
|
-
│ duration: reportData.endTime - reportData.startTime, │
|
|
192
|
-
│ summary, │
|
|
193
|
-
│ toolCalls: reportData.toolCalls.map(sanitizeCall), │
|
|
194
|
-
│ failures │
|
|
195
|
-
│ } │
|
|
196
|
-
│ │
|
|
197
|
-
│ await outputManager.writeFile( │
|
|
198
|
-
│ 'report.json', │
|
|
199
|
-
│ JSON.stringify(jsonReport, null, 2) │
|
|
200
|
-
│ ) │
|
|
201
|
-
│ │
|
|
202
|
-
│ // 4. Generate Markdown report │
|
|
203
|
-
│ const mdReport = generateMarkdown(jsonReport) │
|
|
204
|
-
│ await outputManager.writeFile('report.md', mdReport) │
|
|
205
|
-
│ │
|
|
206
|
-
│ logger.info('Session report generated', { │
|
|
207
|
-
│ sessionId, │
|
|
208
|
-
│ totalCalls: summary.totalCalls, │
|
|
209
|
-
│ successRate: summary.successRate │
|
|
210
|
-
│ }) │
|
|
211
|
-
│ } │
|
|
212
|
-
└──────────────────────────────────────────────────────────────────────┘
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### 2.2 数据流图
|
|
216
|
-
|
|
217
|
-
```
|
|
218
|
-
┌───────────────┐
|
|
219
|
-
│ Tool Call │
|
|
220
|
-
│ Execution │
|
|
221
|
-
└───────┬───────┘
|
|
222
|
-
│
|
|
223
|
-
v
|
|
224
|
-
┌─────────────┐
|
|
225
|
-
│ ToolLogger │
|
|
226
|
-
│ .wrap() │
|
|
227
|
-
└─────┬───────┘
|
|
228
|
-
│
|
|
229
|
-
v
|
|
230
|
-
┌────────────────────────┐
|
|
231
|
-
│ Record to │
|
|
232
|
-
│ session.reportData │
|
|
233
|
-
│ .toolCalls.push() │
|
|
234
|
-
└────────┬───────────────┘
|
|
235
|
-
│
|
|
236
|
-
│ (Continue accumulating)
|
|
237
|
-
v
|
|
238
|
-
┌────────────────────────┐
|
|
239
|
-
│ Session Close │
|
|
240
|
-
│ (dispose triggered) │
|
|
241
|
-
└────────┬───────────────┘
|
|
242
|
-
│
|
|
243
|
-
v
|
|
244
|
-
┌────────────────────────────┐
|
|
245
|
-
│ config.enableSession │
|
|
246
|
-
│ Report === true? │
|
|
247
|
-
└───────┬────────────────────┘
|
|
248
|
-
│
|
|
249
|
-
YES │
|
|
250
|
-
v
|
|
251
|
-
┌────────────────────────────┐
|
|
252
|
-
│ generateSessionReport() │
|
|
253
|
-
│ (async, fire-and-forget) │
|
|
254
|
-
└───────┬────────────────────┘
|
|
255
|
-
│
|
|
256
|
-
│ ┌─ Calculate summary stats
|
|
257
|
-
│ │ (total, success, fail, avg duration)
|
|
258
|
-
│ │
|
|
259
|
-
│ ├─ Extract failures with snapshot links
|
|
260
|
-
│ │
|
|
261
|
-
│ ├─ Generate JSON report
|
|
262
|
-
│ │ └─ Write to report.json
|
|
263
|
-
│ │
|
|
264
|
-
│ └─ Generate Markdown report
|
|
265
|
-
│ └─ Write to report.md
|
|
266
|
-
│
|
|
267
|
-
v
|
|
268
|
-
┌────────────────────────────┐
|
|
269
|
-
│ Report files saved │
|
|
270
|
-
│ - report.json │
|
|
271
|
-
│ - report.md │
|
|
272
|
-
└────────────────────────────┘
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
## 3. 详细设计
|
|
278
|
-
|
|
279
|
-
### 3.1 数据收集流程
|
|
280
|
-
|
|
281
|
-
**初始化** (Session 创建时):
|
|
282
|
-
```typescript
|
|
283
|
-
// src/core/session.ts
|
|
284
|
-
session = {
|
|
285
|
-
sessionId,
|
|
286
|
-
// ... existing fields
|
|
287
|
-
reportData: config.enableSessionReport ? {
|
|
288
|
-
toolCalls: [],
|
|
289
|
-
startTime: new Date(),
|
|
290
|
-
} : undefined,
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
**记录工具调用** (ToolLogger.wrap):
|
|
295
|
-
```typescript
|
|
296
|
-
// src/core/tool-logger.ts
|
|
297
|
-
private recordToolCall(
|
|
298
|
-
session: SessionState,
|
|
299
|
-
toolName: string,
|
|
300
|
-
duration: number,
|
|
301
|
-
success: boolean,
|
|
302
|
-
resultOrError: any
|
|
303
|
-
): void {
|
|
304
|
-
if (!session.reportData) return // Feature disabled
|
|
305
|
-
|
|
306
|
-
const record: ToolCallRecord = {
|
|
307
|
-
timestamp: new Date(),
|
|
308
|
-
toolName,
|
|
309
|
-
duration,
|
|
310
|
-
success,
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (success) {
|
|
314
|
-
record.result = this.sanitizeResult(resultOrError)
|
|
315
|
-
} else {
|
|
316
|
-
const error = resultOrError as Error
|
|
317
|
-
record.error = {
|
|
318
|
-
message: error.message,
|
|
319
|
-
snapshotPath: this.extractSnapshotPath(session, toolName),
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
session.reportData.toolCalls.push(record)
|
|
324
|
-
|
|
325
|
-
// Memory protection: limit to 1000 records
|
|
326
|
-
if (session.reportData.toolCalls.length > 1000) {
|
|
327
|
-
session.reportData.toolCalls.shift() // Remove oldest
|
|
328
|
-
this.logger?.warn('Report data limit reached, oldest record dropped')
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
**提取快照路径**:
|
|
334
|
-
```typescript
|
|
335
|
-
private extractSnapshotPath(
|
|
336
|
-
session: SessionState,
|
|
337
|
-
toolName: string
|
|
338
|
-
): string | undefined {
|
|
339
|
-
// Check if F2 snapshot was created
|
|
340
|
-
const sanitizedToolName = toolName.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
341
|
-
const pattern = new RegExp(`failures/${sanitizedToolName}-.*`)
|
|
342
|
-
|
|
343
|
-
// Search recent logger output for snapshot path
|
|
344
|
-
// (Alternative: ToolLogger could cache last snapshot path)
|
|
345
|
-
return undefined // Simplified for now
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### 3.2 报告生成流程
|
|
350
|
-
|
|
351
|
-
**触发时机** (Session 关闭):
|
|
352
|
-
```typescript
|
|
353
|
-
// src/core/session.ts
|
|
354
|
-
async dispose(): Promise<void> {
|
|
355
|
-
const sessions = Array.from(this.sessions.values())
|
|
356
|
-
|
|
357
|
-
for (const session of sessions) {
|
|
358
|
-
// F3: Generate report before cleanup
|
|
359
|
-
if (session.reportData && this.config?.enableSessionReport) {
|
|
360
|
-
session.reportData.endTime = new Date()
|
|
361
|
-
|
|
362
|
-
void generateSessionReport(session, this.config).catch((error) => {
|
|
363
|
-
console.error(`Failed to generate report for ${session.sessionId}:`, error)
|
|
364
|
-
})
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
await this.delete(session.sessionId)
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
**报告生成器**:
|
|
373
|
-
```typescript
|
|
374
|
-
// src/core/report-generator.ts
|
|
375
|
-
export async function generateSessionReport(
|
|
376
|
-
session: SessionState,
|
|
377
|
-
config: ServerConfig
|
|
378
|
-
): Promise<void> {
|
|
379
|
-
const { sessionId, reportData, outputManager } = session
|
|
380
|
-
|
|
381
|
-
if (!reportData || !outputManager) {
|
|
382
|
-
throw new Error('Missing report data or output manager')
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// 1. Calculate summary
|
|
386
|
-
const summary = calculateSummary(reportData.toolCalls)
|
|
387
|
-
|
|
388
|
-
// 2. Extract failures
|
|
389
|
-
const failures = reportData.toolCalls
|
|
390
|
-
.filter((call) => !call.success)
|
|
391
|
-
.map((call) => ({
|
|
392
|
-
toolName: call.toolName,
|
|
393
|
-
timestamp: call.timestamp.toISOString(),
|
|
394
|
-
error: call.error?.message || 'Unknown error',
|
|
395
|
-
snapshotPath: call.error?.snapshotPath,
|
|
396
|
-
}))
|
|
397
|
-
|
|
398
|
-
// 3. Build JSON report
|
|
399
|
-
const jsonReport: SessionReport = {
|
|
400
|
-
sessionId,
|
|
401
|
-
startTime: reportData.startTime.toISOString(),
|
|
402
|
-
endTime: reportData.endTime!.toISOString(),
|
|
403
|
-
duration: reportData.endTime!.getTime() - reportData.startTime.getTime(),
|
|
404
|
-
summary,
|
|
405
|
-
toolCalls: reportData.toolCalls,
|
|
406
|
-
failures,
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// 4. Write JSON
|
|
410
|
-
await outputManager.writeFile(
|
|
411
|
-
'report.json',
|
|
412
|
-
Buffer.from(JSON.stringify(jsonReport, null, 2))
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
// 5. Generate and write Markdown
|
|
416
|
-
const markdown = generateMarkdownReport(jsonReport)
|
|
417
|
-
await outputManager.writeFile('report.md', Buffer.from(markdown))
|
|
418
|
-
|
|
419
|
-
console.error(`Session report generated: ${sessionId}`)
|
|
420
|
-
}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### 3.3 Markdown 生成
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
function generateMarkdownReport(report: SessionReport): string {
|
|
427
|
-
const duration = formatDuration(report.duration)
|
|
428
|
-
const successRate = ((report.summary.successRate * 100).toFixed(1))
|
|
429
|
-
|
|
430
|
-
let md = `# Session Report: ${report.sessionId}\n\n`
|
|
431
|
-
|
|
432
|
-
// Summary section
|
|
433
|
-
md += `## Summary\n`
|
|
434
|
-
md += `- **Duration**: ${duration}\n`
|
|
435
|
-
md += `- **Total Calls**: ${report.summary.totalCalls}\n`
|
|
436
|
-
md += `- **Success Rate**: ${successRate}% (${report.summary.successCount}/${report.summary.totalCalls})\n`
|
|
437
|
-
md += `- **Average Duration**: ${formatDuration(report.summary.avgDuration)}\n\n`
|
|
438
|
-
|
|
439
|
-
// Tool statistics table
|
|
440
|
-
md += `## Tool Call Statistics\n`
|
|
441
|
-
md += formatToolStatistics(report.toolCalls)
|
|
442
|
-
md += `\n\n`
|
|
443
|
-
|
|
444
|
-
// Failures section
|
|
445
|
-
if (report.failures.length > 0) {
|
|
446
|
-
md += `## Failures\n`
|
|
447
|
-
report.failures.forEach((failure, index) => {
|
|
448
|
-
md += `### ${index + 1}. ${failure.toolName}\n`
|
|
449
|
-
md += `- **Time**: ${failure.timestamp}\n`
|
|
450
|
-
md += `- **Error**: ${failure.error}\n`
|
|
451
|
-
if (failure.snapshotPath) {
|
|
452
|
-
md += `- **Snapshot**: [${failure.snapshotPath}](${failure.snapshotPath})\n`
|
|
453
|
-
}
|
|
454
|
-
md += `\n`
|
|
455
|
-
})
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Timeline (last 20 calls)
|
|
459
|
-
md += `## Timeline (Last 20 Calls)\n`
|
|
460
|
-
md += formatTimeline(report.toolCalls.slice(-20))
|
|
461
|
-
|
|
462
|
-
return md
|
|
463
|
-
}
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
---
|
|
467
|
-
|
|
468
|
-
## 4. 接口设计
|
|
469
|
-
|
|
470
|
-
### 4.1 类型定义
|
|
471
|
-
|
|
472
|
-
```typescript
|
|
473
|
-
// src/types.ts
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Tool call record for session report
|
|
477
|
-
*/
|
|
478
|
-
export interface ToolCallRecord {
|
|
479
|
-
timestamp: Date
|
|
480
|
-
toolName: string
|
|
481
|
-
duration: number // milliseconds
|
|
482
|
-
success: boolean
|
|
483
|
-
result?: any // Sanitized result (success case)
|
|
484
|
-
error?: {
|
|
485
|
-
message: string
|
|
486
|
-
snapshotPath?: string // Link to F2 failure snapshot
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Report data collected during session
|
|
492
|
-
*/
|
|
493
|
-
export interface ReportData {
|
|
494
|
-
toolCalls: ToolCallRecord[]
|
|
495
|
-
startTime: Date
|
|
496
|
-
endTime?: Date
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Session report (JSON format)
|
|
501
|
-
*/
|
|
502
|
-
export interface SessionReport {
|
|
503
|
-
sessionId: string
|
|
504
|
-
startTime: string // ISO 8601
|
|
505
|
-
endTime: string // ISO 8601
|
|
506
|
-
duration: number // milliseconds
|
|
507
|
-
summary: {
|
|
508
|
-
totalCalls: number
|
|
509
|
-
successCount: number
|
|
510
|
-
failureCount: number
|
|
511
|
-
successRate: number // 0-1
|
|
512
|
-
avgDuration: number // milliseconds
|
|
513
|
-
maxDuration: number
|
|
514
|
-
minDuration: number
|
|
515
|
-
}
|
|
516
|
-
toolCalls: ToolCallRecord[]
|
|
517
|
-
failures: Array<{
|
|
518
|
-
toolName: string
|
|
519
|
-
timestamp: string
|
|
520
|
-
error: string
|
|
521
|
-
snapshotPath?: string
|
|
522
|
-
}>
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Server config extension
|
|
527
|
-
*/
|
|
528
|
-
export interface ServerConfig {
|
|
529
|
-
// ... existing fields
|
|
530
|
-
enableSessionReport?: boolean // Enable session report generation (default: false)
|
|
531
|
-
}
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
### 4.2 公开 API
|
|
535
|
-
|
|
536
|
-
```typescript
|
|
537
|
-
// src/core/report-generator.ts
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Generate session report (JSON + Markdown)
|
|
541
|
-
*/
|
|
542
|
-
export async function generateSessionReport(
|
|
543
|
-
session: SessionState,
|
|
544
|
-
config: ServerConfig
|
|
545
|
-
): Promise<void>
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Calculate summary statistics
|
|
549
|
-
*/
|
|
550
|
-
export function calculateSummary(toolCalls: ToolCallRecord[]): SessionReport['summary']
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Generate Markdown report from JSON report
|
|
554
|
-
*/
|
|
555
|
-
export function generateMarkdownReport(report: SessionReport): string
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
---
|
|
559
|
-
|
|
560
|
-
## 5. 数据模型
|
|
561
|
-
|
|
562
|
-
### 5.1 SessionState 扩展
|
|
563
|
-
|
|
564
|
-
```typescript
|
|
565
|
-
export interface SessionState {
|
|
566
|
-
sessionId: string
|
|
567
|
-
// ... existing fields
|
|
568
|
-
reportData?: ReportData // 🆕 Report collection
|
|
569
|
-
}
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### 5.2 ToolCallRecord 结构
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
interface ToolCallRecord {
|
|
576
|
-
timestamp: Date // When the tool was called
|
|
577
|
-
toolName: string // Tool identifier
|
|
578
|
-
duration: number // Execution time in ms
|
|
579
|
-
success: boolean // true = success, false = error
|
|
580
|
-
result?: any // Sanitized result (success)
|
|
581
|
-
error?: { // Error details (failure)
|
|
582
|
-
message: string // Error message
|
|
583
|
-
snapshotPath?: string // Relative path to F2 snapshot
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
**大小估算**:
|
|
589
|
-
- 每条记录约 200-500 bytes (含脱敏数据)
|
|
590
|
-
- 1000 条记录约 200-500 KB
|
|
591
|
-
- 内存限制:单会话最多 1000 条记录
|
|
592
|
-
|
|
593
|
-
### 5.3 JSON Schema
|
|
594
|
-
|
|
595
|
-
```json
|
|
596
|
-
{
|
|
597
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
598
|
-
"type": "object",
|
|
599
|
-
"required": ["sessionId", "startTime", "endTime", "duration", "summary", "toolCalls", "failures"],
|
|
600
|
-
"properties": {
|
|
601
|
-
"sessionId": { "type": "string" },
|
|
602
|
-
"startTime": { "type": "string", "format": "date-time" },
|
|
603
|
-
"endTime": { "type": "string", "format": "date-time" },
|
|
604
|
-
"duration": { "type": "number", "minimum": 0 },
|
|
605
|
-
"summary": {
|
|
606
|
-
"type": "object",
|
|
607
|
-
"required": ["totalCalls", "successCount", "failureCount", "successRate", "avgDuration", "maxDuration", "minDuration"],
|
|
608
|
-
"properties": {
|
|
609
|
-
"totalCalls": { "type": "integer", "minimum": 0 },
|
|
610
|
-
"successCount": { "type": "integer", "minimum": 0 },
|
|
611
|
-
"failureCount": { "type": "integer", "minimum": 0 },
|
|
612
|
-
"successRate": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
613
|
-
"avgDuration": { "type": "number", "minimum": 0 },
|
|
614
|
-
"maxDuration": { "type": "number", "minimum": 0 },
|
|
615
|
-
"minDuration": { "type": "number", "minimum": 0 }
|
|
616
|
-
}
|
|
617
|
-
},
|
|
618
|
-
"toolCalls": {
|
|
619
|
-
"type": "array",
|
|
620
|
-
"items": {
|
|
621
|
-
"type": "object",
|
|
622
|
-
"required": ["timestamp", "toolName", "duration", "success"],
|
|
623
|
-
"properties": {
|
|
624
|
-
"timestamp": { "type": "string", "format": "date-time" },
|
|
625
|
-
"toolName": { "type": "string" },
|
|
626
|
-
"duration": { "type": "number", "minimum": 0 },
|
|
627
|
-
"success": { "type": "boolean" },
|
|
628
|
-
"result": {},
|
|
629
|
-
"error": {
|
|
630
|
-
"type": "object",
|
|
631
|
-
"properties": {
|
|
632
|
-
"message": { "type": "string" },
|
|
633
|
-
"snapshotPath": { "type": "string" }
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
},
|
|
639
|
-
"failures": {
|
|
640
|
-
"type": "array",
|
|
641
|
-
"items": {
|
|
642
|
-
"type": "object",
|
|
643
|
-
"required": ["toolName", "timestamp", "error"],
|
|
644
|
-
"properties": {
|
|
645
|
-
"toolName": { "type": "string" },
|
|
646
|
-
"timestamp": { "type": "string", "format": "date-time" },
|
|
647
|
-
"error": { "type": "string" },
|
|
648
|
-
"snapshotPath": { "type": "string" }
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
---
|
|
657
|
-
|
|
658
|
-
## 6. 错误处理
|
|
659
|
-
|
|
660
|
-
### 6.1 报告生成失败
|
|
661
|
-
|
|
662
|
-
```typescript
|
|
663
|
-
// Fire-and-forget pattern
|
|
664
|
-
void generateSessionReport(session, config).catch((error) => {
|
|
665
|
-
console.error(`Failed to generate report: ${error.message}`)
|
|
666
|
-
// Don't block session closure
|
|
667
|
-
})
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
**错误类型**:
|
|
671
|
-
1. **文件写入失败** (ENOSPC, EACCES)
|
|
672
|
-
- 记录到日志
|
|
673
|
-
- 继续会话关闭
|
|
674
|
-
|
|
675
|
-
2. **数据序列化失败** (循环引用)
|
|
676
|
-
- 使用 try-catch 包裹 JSON.stringify
|
|
677
|
-
- 返回错误占位符
|
|
678
|
-
|
|
679
|
-
3. **内存不足**
|
|
680
|
-
- 限制 toolCalls 数组大小
|
|
681
|
-
- 自动丢弃最早记录
|
|
682
|
-
|
|
683
|
-
### 6.2 数据收集失败
|
|
684
|
-
|
|
685
|
-
```typescript
|
|
686
|
-
// src/core/tool-logger.ts
|
|
687
|
-
try {
|
|
688
|
-
this.recordToolCall(session, toolName, duration, success, result)
|
|
689
|
-
} catch (error) {
|
|
690
|
-
// Don't fail the tool call due to reporting issues
|
|
691
|
-
this.logger?.warn('Failed to record tool call', { error })
|
|
692
|
-
}
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
---
|
|
696
|
-
|
|
697
|
-
## 7. 性能考量
|
|
698
|
-
|
|
699
|
-
### 7.1 内存管理
|
|
700
|
-
|
|
701
|
-
**限制策略**:
|
|
702
|
-
```typescript
|
|
703
|
-
const MAX_TOOL_CALLS = 1000
|
|
704
|
-
|
|
705
|
-
if (session.reportData.toolCalls.length >= MAX_TOOL_CALLS) {
|
|
706
|
-
session.reportData.toolCalls.shift() // FIFO
|
|
707
|
-
logger.warn('Report data limit reached')
|
|
708
|
-
}
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
**内存占用估算**:
|
|
712
|
-
- 每条记录: 200-500 bytes
|
|
713
|
-
- 1000 条记录: 200-500 KB
|
|
714
|
-
- 可接受范围(相比会话其他数据)
|
|
715
|
-
|
|
716
|
-
### 7.2 生成性能
|
|
717
|
-
|
|
718
|
-
**优化措施**:
|
|
719
|
-
1. **Fire-and-forget**: 不阻塞会话关闭
|
|
720
|
-
2. **流式写入**: 对大型报告使用流式写入
|
|
721
|
-
3. **延迟序列化**: 仅在生成时序列化
|
|
722
|
-
|
|
723
|
-
**性能目标**:
|
|
724
|
-
- 报告生成耗时 < 200ms (1000 条记录)
|
|
725
|
-
- 不影响会话关闭速度
|
|
726
|
-
|
|
727
|
-
---
|
|
728
|
-
|
|
729
|
-
## 8. 安全性
|
|
730
|
-
|
|
731
|
-
### 8.1 数据脱敏
|
|
732
|
-
|
|
733
|
-
**复用 F1 逻辑**:
|
|
734
|
-
```typescript
|
|
735
|
-
record.result = this.sanitizeResult(result)
|
|
736
|
-
record.args = this.sanitizeArgs(args)
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
**脱敏规则**:
|
|
740
|
-
- 移除敏感字段 (password, token, apiKey, etc.)
|
|
741
|
-
- 截断大字符串 (>1KB)
|
|
742
|
-
- 处理循环引用
|
|
743
|
-
|
|
744
|
-
### 8.2 文件权限
|
|
745
|
-
|
|
746
|
-
**报告文件位置**:
|
|
747
|
-
```
|
|
748
|
-
.mcp-artifacts/{sessionId}/
|
|
749
|
-
├─ report.json (644)
|
|
750
|
-
└─ report.md (644)
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
**注意事项**:
|
|
754
|
-
- 报告文件可能包含业务敏感信息
|
|
755
|
-
- 建议在 .gitignore 中排除 .mcp-artifacts/
|
|
756
|
-
- 文档提醒用户注意报告文件的访问控制
|
|
757
|
-
|
|
758
|
-
---
|
|
759
|
-
|
|
760
|
-
## 9. 测试策略
|
|
761
|
-
|
|
762
|
-
### 9.1 单元测试
|
|
763
|
-
|
|
764
|
-
**数据收集测试**:
|
|
765
|
-
```typescript
|
|
766
|
-
it('should record successful tool call', async () => {
|
|
767
|
-
const session = createMockSession({ enableSessionReport: true })
|
|
768
|
-
const toolLogger = new ToolLogger(mockLogger, config)
|
|
769
|
-
const handler = jest.fn().mockResolvedValue({ success: true })
|
|
770
|
-
|
|
771
|
-
const wrapped = toolLogger.wrap('test_tool', handler)
|
|
772
|
-
await wrapped(session, { arg: 'value' })
|
|
773
|
-
|
|
774
|
-
expect(session.reportData.toolCalls).toHaveLength(1)
|
|
775
|
-
expect(session.reportData.toolCalls[0]).toMatchObject({
|
|
776
|
-
toolName: 'test_tool',
|
|
777
|
-
success: true,
|
|
778
|
-
duration: expect.any(Number),
|
|
779
|
-
})
|
|
780
|
-
})
|
|
781
|
-
```
|
|
782
|
-
|
|
783
|
-
**报告生成测试**:
|
|
784
|
-
```typescript
|
|
785
|
-
it('should generate valid JSON report', async () => {
|
|
786
|
-
const session = createSessionWithMockData()
|
|
787
|
-
await generateSessionReport(session, config)
|
|
788
|
-
|
|
789
|
-
const reportPath = join(session.outputDir, 'report.json')
|
|
790
|
-
const content = await readFile(reportPath, 'utf-8')
|
|
791
|
-
const report = JSON.parse(content)
|
|
792
|
-
|
|
793
|
-
expect(report).toMatchSchema(SessionReportSchema)
|
|
794
|
-
expect(report.summary.totalCalls).toBe(10)
|
|
795
|
-
expect(report.summary.successRate).toBeCloseTo(0.8)
|
|
796
|
-
})
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
### 9.2 集成测试
|
|
800
|
-
|
|
801
|
-
**端到端流程**:
|
|
802
|
-
```typescript
|
|
803
|
-
it('should generate report on session close', async () => {
|
|
804
|
-
const sessionStore = new SessionStore({ enableSessionReport: true })
|
|
805
|
-
const session = sessionStore.getOrCreate('test-session')
|
|
806
|
-
|
|
807
|
-
// Execute some tools
|
|
808
|
-
await executeMockToolCalls(session, 10) // 8 success, 2 fail
|
|
809
|
-
|
|
810
|
-
// Close session
|
|
811
|
-
await sessionStore.dispose()
|
|
812
|
-
|
|
813
|
-
// Verify report files exist
|
|
814
|
-
const reportJsonPath = join(session.outputDir, 'report.json')
|
|
815
|
-
const reportMdPath = join(session.outputDir, 'report.md')
|
|
816
|
-
|
|
817
|
-
expect(await fileExists(reportJsonPath)).toBe(true)
|
|
818
|
-
expect(await fileExists(reportMdPath)).toBe(true)
|
|
819
|
-
|
|
820
|
-
// Verify content
|
|
821
|
-
const report = JSON.parse(await readFile(reportJsonPath, 'utf-8'))
|
|
822
|
-
expect(report.summary.totalCalls).toBe(10)
|
|
823
|
-
expect(report.summary.failureCount).toBe(2)
|
|
824
|
-
})
|
|
825
|
-
```
|
|
826
|
-
|
|
827
|
-
### 9.3 性能测试
|
|
828
|
-
|
|
829
|
-
```typescript
|
|
830
|
-
it('should handle 1000 tool calls efficiently', async () => {
|
|
831
|
-
const session = createMockSession({ enableSessionReport: true })
|
|
832
|
-
|
|
833
|
-
const startTime = Date.now()
|
|
834
|
-
for (let i = 0; i < 1000; i++) {
|
|
835
|
-
recordToolCall(session, 'test_tool', 100, true, {})
|
|
836
|
-
}
|
|
837
|
-
const duration = Date.now() - startTime
|
|
838
|
-
|
|
839
|
-
expect(duration).toBeLessThan(100) // <100ms for 1000 records
|
|
840
|
-
expect(session.reportData.toolCalls).toHaveLength(1000)
|
|
841
|
-
})
|
|
842
|
-
```
|
|
843
|
-
|
|
844
|
-
---
|
|
845
|
-
|
|
846
|
-
## 附录
|
|
847
|
-
|
|
848
|
-
### A. Markdown 示例输出
|
|
849
|
-
|
|
850
|
-
```markdown
|
|
851
|
-
# Session Report: test-session-abc123
|
|
852
|
-
|
|
853
|
-
## Summary
|
|
854
|
-
- **Duration**: 15m 30s
|
|
855
|
-
- **Total Calls**: 50
|
|
856
|
-
- **Success Rate**: 94.0% (47/50)
|
|
857
|
-
- **Average Duration**: 1.5s
|
|
858
|
-
|
|
859
|
-
## Tool Call Statistics
|
|
860
|
-
| Tool Name | Calls | Success | Failure | Avg Duration |
|
|
861
|
-
|-----------|-------|---------|---------|--------------|
|
|
862
|
-
| miniprogram_launch | 1 | 1 | 0 | 3.0s |
|
|
863
|
-
| page_navigate | 5 | 5 | 0 | 0.8s |
|
|
864
|
-
| element_click | 10 | 8 | 2 | 0.5s |
|
|
865
|
-
| element_input | 8 | 8 | 0 | 0.3s |
|
|
866
|
-
| assert_exists | 15 | 15 | 0 | 0.2s |
|
|
867
|
-
| snapshot_page | 3 | 3 | 0 | 1.2s |
|
|
868
|
-
|
|
869
|
-
## Failures
|
|
870
|
-
### 1. element_click
|
|
871
|
-
- **Time**: 2025-10-03T06:05:10.123Z
|
|
872
|
-
- **Error**: Element not found: #submit-button
|
|
873
|
-
- **Snapshot**: [failures/element_click-2025-10-03_06-05-10-123Z](failures/element_click-2025-10-03_06-05-10-123Z)
|
|
874
|
-
|
|
875
|
-
### 2. element_click
|
|
876
|
-
- **Time**: 2025-10-03T06:12:45.789Z
|
|
877
|
-
- **Error**: Element is not clickable
|
|
878
|
-
- **Snapshot**: [failures/element_click-2025-10-03_06-12-45-789Z](failures/element_click-2025-10-03_06-12-45-789Z)
|
|
879
|
-
|
|
880
|
-
## Timeline (Last 20 Calls)
|
|
881
|
-
| Time | Tool | Status | Duration |
|
|
882
|
-
|------|------|--------|----------|
|
|
883
|
-
| 06:00:05 | miniprogram_launch | ✅ | 3.0s |
|
|
884
|
-
| 06:00:08 | page_navigate | ✅ | 0.8s |
|
|
885
|
-
| 06:01:15 | element_input | ✅ | 0.3s |
|
|
886
|
-
| 06:05:10 | element_click | ❌ | 0.5s |
|
|
887
|
-
| ... | ... | ... | ... |
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
### B. 配置示例
|
|
891
|
-
|
|
892
|
-
```typescript
|
|
893
|
-
// Enable session report
|
|
894
|
-
const server = new Server({
|
|
895
|
-
enableSessionReport: true, // 🆕 Generate report.json and report.md
|
|
896
|
-
enableFailureSnapshot: true, // F2 integration
|
|
897
|
-
logLevel: 'info',
|
|
898
|
-
})
|
|
899
|
-
```
|
|
900
|
-
|
|
901
|
-
---
|
|
902
|
-
|
|
903
|
-
**文档版本**: 1.0
|
|
904
|
-
**最后更新**: 2025-10-03
|
|
905
|
-
**作者**: ClaudeCode
|