558 lines
18 KiB
Markdown
558 lines
18 KiB
Markdown
# ISS-010 同 session 多轮诊断 Trace 隔离
|
||
|
||
**状态**:OpenSpec 已创建,Phase 1 已完成,Phase 2 进行中
|
||
**严重程度**:高
|
||
**发现时间**:2026-07-10
|
||
**来源**:同一 `sessionId` 多轮 Chat E2E 验证
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
当前 Chat 链路同时存在两类“会话”语义:
|
||
|
||
```text
|
||
Redis SessionContext
|
||
-> 保存同一 sessionId 的多轮对话历史
|
||
-> 用于下一轮模型上下文
|
||
|
||
MySQL diagnosis_session / agent_step / tool_invocation
|
||
-> 保存诊断 Trace
|
||
-> 用于 Trace API、Verifier、Evidence score、Feedback 和评测
|
||
```
|
||
|
||
多轮对话需要继续复用 `sessionId`,否则无法保留上下文。但一次诊断 Trace 应该是可独立回放、可独立评分、可独立反馈的执行单元。
|
||
|
||
当前实现只按 `sessionId` 关联 Trace,导致同一个 `sessionId` 下多轮诊断的 step/tool 记录混在一起。
|
||
|
||
---
|
||
|
||
## E2E 证据
|
||
|
||
本次使用 `mvp-demo` profile 通过 Maven 启动服务,并用同一个 `sessionId` 连续请求两轮 `/api/chat`:
|
||
|
||
```text
|
||
sessionId = e2e-multiturn-codex-20260710-1615
|
||
round 1 = 支付接口最近出现超时,请结合知识库、日志和指标判断可能原因,并给出修复建议。
|
||
round 2 = 基于上一轮结论,只列出目前最缺的三类证据,以及下一步应该优先查哪个系统。
|
||
```
|
||
|
||
验证结果:
|
||
|
||
- 第一轮成功,走多 Agent:`planner -> executor -> verifier -> composer`。
|
||
- 第二轮成功,日志显示进入请求时 `会话历史消息对数: 1`,说明 Redis 历史上下文被复用。
|
||
- `/api/chat/session/{sessionId}` 返回 `messagePairCount=2`。
|
||
- `diagnosis_session` 只有一行,`query` 被第二轮问题覆盖。
|
||
- `agent_step` 返回 14 行,包含第一轮多 Agent step 和第二轮 `intelligent_assistant` step。
|
||
- `tool_invocation` 返回 19 行,包含两轮工具调用。
|
||
- `self_evaluation.verifier_evaluation` 仍保留第一轮 Verifier 结果;第二轮简单问答没有新的 Verifier,但 rule evaluation 会基于同 session 全部工具调用重新计算。
|
||
|
||
关键入库形态:
|
||
|
||
```text
|
||
diagnosis_session
|
||
session_id = e2e-multiturn-codex-20260710-1615
|
||
query = round 2 question
|
||
status = SUCCESS
|
||
step_count = 14
|
||
tool_call_count = 19
|
||
|
||
agent_step
|
||
round 1: planner, executor..., verifier, composer
|
||
round 2: intelligent_assistant...
|
||
|
||
tool_invocation
|
||
round 1 tools + round 2 tools all under same session_id
|
||
```
|
||
|
||
本次验证产物保存在:
|
||
|
||
- `target/e2e/request-round1.json`
|
||
- `target/e2e/response-round1.json`
|
||
- `target/e2e/request-round2.json`
|
||
- `target/e2e/response-round2.json`
|
||
- `target/e2e/trace-after-round2.json`
|
||
|
||
---
|
||
|
||
## 核心问题
|
||
|
||
### P0:Trace 不是单次诊断的稳定回放
|
||
|
||
`GET /api/diagnosis/{sessionId}/trace` 会聚合同一 `sessionId` 下所有 `agent_step` 和 `tool_invocation`。
|
||
|
||
多轮之后,Trace 不再表示某一轮诊断,而是混合历史执行轨迹。
|
||
|
||
### P0:Verifier 和评分可能读取跨轮证据
|
||
|
||
Verifier、Gatekeeper、`ToolTraceSummaryService` 和 `EvaluationService` 当前主要按 `sessionId` 查询工具调用。
|
||
|
||
如果上一轮和当前轮证据混在一起,当前轮可能引用或评分到历史工具结果。
|
||
|
||
### P1:反馈语义不清晰
|
||
|
||
`feedback` 当前在 `diagnosis_session` 上按 `sessionId` 保存。
|
||
|
||
多轮之后,用户反馈的是哪一轮答案不再明确。`useful` 反馈沉淀到 `case_library` 时也可能关联到最新主表答案,而不是用户实际评价的那一轮。
|
||
|
||
### P1:`diagnosis_session` 字段被覆盖但子表追加
|
||
|
||
主表 `query/answer/status/self_evaluation/step_count/tool_call_count` 表示最新运行或混合统计,子表却保留多轮历史。
|
||
|
||
这会让 Trace summary、数据库统计和人工排查产生歧义。
|
||
|
||
---
|
||
|
||
## 已确认决策
|
||
|
||
### D1:`runId` 是正式 API 字段
|
||
|
||
`/api/chat` 和 `/api/ai_ops` 的响应或 SSE 消息需要暴露本次执行的 `runId`。
|
||
|
||
```text
|
||
sessionId = 多轮对话上下文 ID
|
||
runId = 本轮诊断执行 ID
|
||
```
|
||
|
||
新客户端应优先用 `runId` 查询 Trace 和提交 Feedback。旧客户端只传 `sessionId` 时,服务端兼容解析该 session 的最新 run。
|
||
|
||
### D2:拆分会话态和运行态
|
||
|
||
不再把 session、run、trace 全部塞进 `diagnosis_session` 一张主表。
|
||
|
||
新增两张主表:
|
||
|
||
```text
|
||
chat_session
|
||
-> 多轮对话上下文主表
|
||
|
||
diagnosis_run
|
||
-> 单次诊断执行主表
|
||
```
|
||
|
||
Trace 继续使用现有明细表表达:
|
||
|
||
```text
|
||
agent_step
|
||
tool_invocation
|
||
```
|
||
|
||
暂不新增单独的 `diagnosis_trace` 或 `trace_event` 主表。
|
||
|
||
### D3:`runId` 格式
|
||
|
||
使用 `run-` + UUID 全量字符串。
|
||
|
||
```text
|
||
run-550e8400-e29b-41d4-a716-446655440000
|
||
```
|
||
|
||
### D4:Trace API 兼容旧路径
|
||
|
||
```text
|
||
GET /api/diagnosis/{sessionId}/trace
|
||
-> 查该 session 最新 run
|
||
|
||
GET /api/diagnosis/{sessionId}/trace?runId=run-xxx
|
||
-> 查指定 run
|
||
```
|
||
|
||
指定 `runId` 时必须校验该 run 属于 path 中的 `sessionId`。
|
||
|
||
最新 run 建议按 `diagnosis_run.created_at DESC, id DESC` 解析,避免旧 run 因反馈或异步评分更新 `updated_at` 后被误认为最新。
|
||
|
||
### D5:Feedback 优先绑定 run
|
||
|
||
Feedback request 支持 `runId`。
|
||
|
||
- 有 `runId`:绑定指定 run。
|
||
- 无 `runId`:短期兼容绑定该 `sessionId` 最新 run,并显式标记 fallback。
|
||
- `case_library.diagnosis_id` 新数据保存 `run_id`。
|
||
|
||
兼容语义:历史 `case_library.diagnosis_id` 可能保存 `diagnosis_session.session_id`;本 change 之后自动沉淀的新数据保存 `diagnosis_run.run_id`。查询、幂等和文档需要在过渡期识别两种来源,避免把旧案例误判为无效数据。
|
||
|
||
### D6:所有 `/api/chat` 执行请求都创建 run
|
||
|
||
只要请求通过参数校验并进入 `ChatService.executeChatWithStrategy`,就创建新的 diagnosis run。
|
||
|
||
- 简单问答也创建 run。
|
||
- 复杂诊断也创建 run。
|
||
- 空问题等参数校验失败不创建 run。
|
||
|
||
### D7:AIOps 同步纳入 run 隔离
|
||
|
||
每次 `/api/ai_ops` 执行也创建新的 diagnosis run。AIOps 的 step、tool invocation 和 rule evaluation 都按 `runId` 隔离。
|
||
|
||
阶段说明:AIOps 可作为独立实现切片排在 Chat 之后,但必须在本 change 整体完成前落地;Chat-only 的中间状态只能作为过渡验证状态,不能作为生产完成状态归档。
|
||
|
||
### D8:`chat_session` 第一阶段只保存会话元数据
|
||
|
||
`chat_session` 是会话目录/索引表,不保存完整对话历史正文。
|
||
|
||
建议保存:
|
||
|
||
```text
|
||
session_id
|
||
status
|
||
message_pair_count
|
||
created_at
|
||
last_active_at
|
||
expires_at
|
||
```
|
||
|
||
完整多轮对话历史继续放在 Redis `SessionContext.messageHistory`,用于下一轮 prompt 上下文。
|
||
|
||
每轮需要长期审计的用户问题和最终回答保存到 `diagnosis_run.query` / `diagnosis_run.answer`。
|
||
|
||
`chat_session.expires_at` 只表示 MySQL 会话目录的过期/清理元数据;Redis TTL 到期后,`SessionContext.messageHistory` 可能不再存在,但已经持久化的 `diagnosis_run`、`agent_step` 和 `tool_invocation` 仍作为审计记录保留。
|
||
|
||
如果未来需要长期保存完整聊天历史,再单独设计 `chat_message` 表,不在本阶段引入。
|
||
|
||
### D9:旧 `diagnosis_session` 表保留但新代码不再写入
|
||
|
||
新增 `diagnosis_run` 后,旧 `diagnosis_session` 不立即删除、不立即改造成 view、不直接重命名。
|
||
|
||
迁移策略:
|
||
|
||
1. 新增 `chat_session` / `diagnosis_run`。
|
||
2. 为 `agent_step` / `tool_invocation` 新增 nullable `run_id`。
|
||
3. 将旧 `diagnosis_session` 数据迁移/复制为 `diagnosis_run` 兼容记录。
|
||
4. 为旧 `agent_step` / `tool_invocation` 回填对应 `run_id`。
|
||
5. 增加必要索引和查询方法,先保持兼容读取。
|
||
6. 新代码切换为只写 `chat_session` 和 `diagnosis_run`,并为新 step/tool 写入 `run_id`。
|
||
7. 验证新旧数据 `run_id` 覆盖情况后,再将新写路径要求 `run_id` 非空,并补充索引/约束。
|
||
8. 旧 `diagnosis_session` 暂时保留,用于历史核对和回滚窗口。
|
||
9. 后续确认无依赖后,再单独归档或删除旧表。
|
||
|
||
### D10:提供轻量 run 列表 API
|
||
|
||
新增轻量查询接口,用于查看一个 Chat Session 下有哪些 Diagnosis Run。
|
||
|
||
```text
|
||
GET /api/chat/session/{sessionId}/runs
|
||
```
|
||
|
||
建议返回字段:
|
||
|
||
```text
|
||
runId
|
||
sessionId
|
||
query
|
||
status
|
||
agentFlow
|
||
answerPreview
|
||
stepCount
|
||
toolCallCount
|
||
createdAt
|
||
updatedAt
|
||
```
|
||
|
||
该接口只读 `diagnosis_run` 主表,不展开 `agent_step` / `tool_invocation` 大字段。
|
||
|
||
### D11:Feedback 缺少 `runId` 时短期兼容,长期收紧
|
||
|
||
Feedback 新协议优先要求 `runId`。
|
||
|
||
短期兼容策略:
|
||
|
||
- 有 `runId`:绑定指定 run。
|
||
- 无 `runId`:绑定该 `sessionId` 最新 run。
|
||
- 无 `runId` fallback 时,在响应或日志中明确标记 `fallbackToLatestRun=true`,并返回实际绑定的 `runId`。
|
||
|
||
长期收紧策略:
|
||
|
||
- 当前端、demo 脚本和外部调用方都完成 `runId` 传递后,再评估是否将缺少 `runId` 改为参数错误。
|
||
|
||
### D12:同步更新 demo 脚本和 Trace UI 的 `runId` 最小支持
|
||
|
||
本 issue 实施范围包含 demo 脚本和 Trace UI 的最小协议适配。
|
||
|
||
范围:
|
||
|
||
- Demo 脚本读取 `/api/chat` 或 `/api/ai_ops` 返回的 `runId`。
|
||
- Demo 脚本查询 Trace 时传 `?runId=...`。
|
||
- Trace UI 支持 URL 参数 `?sessionId=...&runId=...`。
|
||
- Trace UI 查询时如果有 `runId`,带上 `runId`。
|
||
- 不在本阶段实现完整 run 列表 UI。
|
||
|
||
---
|
||
|
||
## 目标语义
|
||
|
||
引入明确的 `sessionId` / `runId` 分层:
|
||
|
||
```text
|
||
sessionId = 多轮对话上下文
|
||
runId = 单次诊断执行 / 单次可回放 Trace
|
||
```
|
||
|
||
目标关系:
|
||
|
||
```text
|
||
chat_session(sessionId)
|
||
-> one conversation context
|
||
-> conversation metadata / TTL / last active state
|
||
|
||
Redis SessionContext(sessionId)
|
||
-> hot messageHistory cache
|
||
-> supports prompt context window
|
||
|
||
diagnosis_run(runId, sessionId)
|
||
-> one diagnosis run
|
||
|
||
agent_step(runId, sessionId)
|
||
-> steps of one run
|
||
|
||
tool_invocation(runId, sessionId)
|
||
-> tool calls of one run
|
||
```
|
||
|
||
---
|
||
|
||
## 建议方案
|
||
|
||
采用“拆分主表 + 复用现有 Trace 明细表”的方案:
|
||
|
||
1. 新增 `chat_session`。
|
||
2. 新增 `diagnosis_run`。
|
||
3. 逐步迁移当前 `diagnosis_session` 语义到 `diagnosis_run`。
|
||
4. `agent_step` 新增 `run_id`,继续保留 `session_id` 作为冗余筛选和兼容字段。
|
||
5. `tool_invocation` 新增 `run_id`,继续保留 `session_id` 作为冗余筛选和兼容字段。
|
||
6. Trace API 聚合 `diagnosis_run + agent_step + tool_invocation`。
|
||
|
||
建议核心字段:
|
||
|
||
```text
|
||
chat_session
|
||
id
|
||
session_id unique
|
||
status
|
||
message_pair_count
|
||
created_at
|
||
last_active_at
|
||
expires_at
|
||
|
||
diagnosis_run
|
||
id
|
||
run_id unique
|
||
session_id
|
||
query
|
||
status
|
||
agent_flow
|
||
answer
|
||
self_evaluation
|
||
feedback
|
||
total_duration_ms
|
||
total_token_count
|
||
step_count
|
||
tool_call_count
|
||
created_at
|
||
updated_at
|
||
|
||
agent_step(run_id, step_index)
|
||
tool_invocation(run_id, id)
|
||
```
|
||
|
||
理由:
|
||
|
||
- `chat_session` 只表达会话态,避免会话上下文和诊断结果混在一起。
|
||
- `diagnosis_run` 只表达一次执行,天然隔离每轮 Trace、评分和反馈。
|
||
- `agent_step` / `tool_invocation` 已足够表达 Trace 明细,暂不需要额外 trace 主表。
|
||
- 后续如果需要统一时间线,再增加 `trace_event`,不阻塞本次隔离。
|
||
|
||
---
|
||
|
||
## 分阶段计划
|
||
|
||
### Phase 0:协议基线和数据边界
|
||
|
||
目标:先把语义定死,避免实现中反复。
|
||
|
||
已确认基线:
|
||
|
||
1. `/api/chat` 是否返回 `runId`。
|
||
2. `GET /api/diagnosis/{sessionId}/trace` 默认查最新 run 还是要求显式传 `runId`。
|
||
3. Feedback 是否优先绑定 `runId`,只有旧请求缺失 `runId` 时才回退最新 run。
|
||
4. AIOps 是否和 Chat 同步接入 `runId`。
|
||
5. 简单问答是否也创建 diagnosis run。
|
||
|
||
建议默认:
|
||
|
||
- `/api/chat` 返回 `sessionId + runId`。
|
||
- `GET /api/diagnosis/{sessionId}/trace` 兼容查最新 run。
|
||
- `GET /api/diagnosis/{sessionId}/trace?runId=...` 查指定 run。
|
||
- Feedback 优先按 `runId` 绑定。
|
||
- Chat 简单问答也创建 run。
|
||
- AIOps 同步接入 run 隔离。
|
||
|
||
### Phase 1:Schema 迁移和历史数据兼容
|
||
|
||
目标:引入 `chat_session` / `diagnosis_run`,并保留旧数据可查询。
|
||
|
||
任务:
|
||
|
||
- Flyway 新增 `chat_session`。
|
||
- Flyway 新增 `diagnosis_run`。
|
||
- 为旧 `diagnosis_session` 生成兼容 `diagnosis_run` 记录。
|
||
- 为旧 `agent_step` / `tool_invocation` 回填对应 `run_id`。
|
||
- 增加 `find latest run by sessionId` 查询。
|
||
- 增加 `find by runId` 查询。
|
||
- 保留旧 `diagnosis_session` 一段时间,新代码不再写入。
|
||
|
||
验收:
|
||
|
||
- 旧 session 的 Trace 仍可查。
|
||
- 新索引存在。
|
||
- 不改变旧 `/api/chat` 必需字段。
|
||
- `agent_step` / `tool_invocation` 支持 nullable `run_id` 并完成旧数据回填。
|
||
- 新增 repository 查询可以按 `sessionId` 找最新 run、按 `runId` 找指定 run。
|
||
|
||
### Phase 2:Chat 写入切到 runId
|
||
|
||
目标:每轮 `/api/chat` 创建一个新的 run,step/tool 按 run 隔离。
|
||
|
||
任务:
|
||
|
||
- `ChatService` 每次执行生成新的 `runId`。
|
||
- `ChatController` 确保 `chat_session` 存在并更新会话态。
|
||
- `ChatService` 按 `runId` 创建 `diagnosis_run`。
|
||
- `AgentLoggingHook` 写入 `agent_step.run_id`。
|
||
- `ToolInvocationRecorder` 写入 `tool_invocation.run_id`。
|
||
- `SessionContextHolder` 或新的上下文 holder 同时携带 `sessionId + runId`。
|
||
- `backfillSessionMetrics` 按 `runId` 统计。
|
||
- `EvaluationService` 按 `runId` 读取工具调用。
|
||
|
||
验收:
|
||
|
||
- 同一 `sessionId` 连续两轮后,`diagnosis_run` 有两行不同 `run_id`。
|
||
- `/api/chat` 响应增加正式字段 `runId`。
|
||
- 两轮 `agent_step` / `tool_invocation` 分别按各自 `run_id` 查询。
|
||
- Redis `messagePairCount` 仍为 2,证明上下文不被破坏。
|
||
|
||
### Phase 3:Trace API 兼容和精确查询
|
||
|
||
目标:Trace API 可查最新 run,也可查指定 run,并能列出一个 session 下的 run。
|
||
|
||
任务:
|
||
|
||
- `GET /api/diagnosis/{sessionId}/trace` 从 `diagnosis_run` 默认解析最新 run。
|
||
- 增加 `runId` query 参数。
|
||
- Trace response 增加 `runId`。
|
||
- 新增 `GET /api/chat/session/{sessionId}/runs`。
|
||
|
||
验收:
|
||
|
||
- 不传 `runId` 返回最新 run。
|
||
- 传第一轮 `runId` 只返回第一轮 step/tool。
|
||
- 传第二轮 `runId` 只返回第二轮 step/tool。
|
||
- run 列表 API 只返回轻量 run 摘要,不展开 trace 明细。
|
||
- Demo 脚本和 Trace UI 的 `runId` 最小适配按 OpenSpec tasks 放到 Phase 6,避免 Phase 3 同时混入前端/脚本范围。
|
||
|
||
### Phase 4:Feedback 和 CaseLibrary 绑定 run
|
||
|
||
目标:反馈明确评价哪一轮诊断。
|
||
|
||
任务:
|
||
|
||
- Feedback request 支持 `runId`。
|
||
- 旧请求只有 `sessionId` 时短期绑定最新 run,并显式标记 fallback。
|
||
- `case_library.diagnosis_id` 新数据保存 `run_id`。
|
||
- `CaseLibraryService` 以 run 为来源生成 case,并用 `run_id` 做新数据幂等键。
|
||
- 文档说明 `diagnosis_id` 的过渡语义:旧数据可能是 `session_id`,新数据是 `run_id`。
|
||
|
||
验收:
|
||
|
||
- 同 session 多轮后,对第一轮提交 feedback 不会覆盖第二轮。
|
||
- useful 生成 case 时能定位到对应 run 的 query/answer。
|
||
|
||
### Phase 5:AIOps 同步 run 隔离
|
||
|
||
目标:AIOps 使用同样的 run 语义,避免另一条入口继续混杂。
|
||
|
||
任务:
|
||
|
||
- `AiOpsService` 生成并返回/透出 `runId`。
|
||
- AIOps `agent_step` / `tool_invocation` 按 `runId` 隔离。
|
||
- AIOps rule evaluation 写入当前 run 的 `diagnosis_run.self_evaluation.aiops_rule_evaluation`。
|
||
- AIOps Trace 查询兼容 `sessionId + runId`。
|
||
|
||
验收:
|
||
|
||
- 同一 AIOps `sessionId` 重跑不会混合 step/tool。
|
||
- AIOps rule evaluation 只读取当前 run 工具调用。
|
||
|
||
---
|
||
|
||
## 暂不做
|
||
|
||
1. 暂不新增 `diagnosis_trace` 或 `trace_event` 主表。
|
||
2. 暂不做完整 run 列表 UI。
|
||
3. 暂不删除历史 Trace 数据。
|
||
4. 暂不改变 Redis 多轮上下文窗口策略。
|
||
5. 暂不立即物理删除旧 `diagnosis_session` 表。
|
||
|
||
---
|
||
|
||
## 风险
|
||
|
||
### 1. 兼容风险
|
||
|
||
现有脚本、Trace 页面和反馈接口可能只知道 `sessionId`。
|
||
|
||
缓解:保留 `sessionId` 默认查最新 run 的行为。
|
||
|
||
### 2. 异步上下文风险
|
||
|
||
工具调用和 Agent hook 依赖 ThreadLocal / RunnableConfig 传递上下文。
|
||
|
||
缓解:统一上下文对象,明确 `sessionId` 和 `runId` 必须同时传递。
|
||
|
||
### 3. 历史数据回填风险
|
||
|
||
旧数据没有真实 run 边界,只能按当前 `diagnosis_session` 生成一条兼容 `diagnosis_run`。
|
||
|
||
缓解:旧数据视为单 run,不尝试拆分历史混合数据。
|
||
|
||
### 4. 评分口径变化风险
|
||
|
||
按 `runId` 隔离后,工具调用数和 evidence score 可能下降,但语义更正确。
|
||
|
||
缓解:更新 eval fixture 和 baseline,记录这是预期行为变化。
|
||
|
||
---
|
||
|
||
## 已收敛问题
|
||
|
||
本 issue 当前已经收敛以下设计边界:
|
||
|
||
- `runId` 是正式 API 字段。
|
||
- `chat_session` 和 `diagnosis_run` 拆分为两张主表。
|
||
- Trace 明细继续由 `agent_step` / `tool_invocation` 承载。
|
||
- `chat_session` 只保存元数据,不保存完整对话历史。
|
||
- 旧 `diagnosis_session` 保留但新代码不再写入。
|
||
- 提供轻量 run 列表 API。
|
||
- Feedback 缺少 `runId` 时短期兼容、长期收紧。
|
||
- Demo 脚本和 Trace UI 做 `runId` 最小支持。
|
||
|
||
---
|
||
|
||
## 相关文件
|
||
|
||
- `mvp/architecture/session-trace-lifecycle.md`
|
||
- `mvp/architecture/data-model.md`
|
||
- `mvp/tables/诊断会话表-diagnosis_session.md`
|
||
- `mvp/tables/Agent步骤表-agent_step.md`
|
||
- `mvp/tables/工具调用表-tool_invocation.md`
|
||
- `mvp/tables/案例库表-case_library.md`
|
||
- `src/main/java/com/superbiz/agent/controller/ChatController.java`
|
||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||
- `src/main/java/com/superbiz/agent/service/AiOpsService.java`
|
||
- `src/main/java/com/superbiz/agent/service/DiagnosisTraceService.java`
|
||
- `src/main/java/com/superbiz/agent/service/EvaluationService.java`
|
||
- `src/main/java/com/superbiz/agent/service/FeedbackService.java`
|
||
- `src/main/java/com/superbiz/agent/service/CaseLibraryService.java`
|
||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
|
||
- `src/main/java/com/superbiz/agent/service/ToolInvocationRecorder.java`
|
||
- `src/main/java/com/superbiz/agent/util/SessionContextHolder.java`
|
||
- `src/main/resources/db/migration/V005__create_session_storage.sql`
|