Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
Ftt_Common
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Ftt_Common
Commits
2f8390cb
Commit
2f8390cb
authored
Oct 19, 2026
by
段廷瑞
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 对话上报功能,用于对话分析与监控
parent
bf290b43
Changes
17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1655 additions
and
5 deletions
+1655
-5
Tools.Agent.dll
AppHome/Tools.Agent.dll
+0
-0
Tools.Agent.xml
AppHome/Tools.Agent.xml
+159
-1
Program.cs
Tools.Agent.Host/Program.cs
+1
-1
Program.cs
Tools.Agent.ProbeRunDb/Program.cs
+59
-0
Tools.Agent.ProbeRunDb.csproj
Tools.Agent.ProbeRunDb/Tools.Agent.ProbeRunDb.csproj
+35
-0
AgentEngine.cs
Tools.Agent/Agent/AgentEngine.cs
+10
-1
AgentRuntime.cs
Tools.Agent/AgentRuntime.cs
+30
-2
AgentConfig.cs
Tools.Agent/Config/AgentConfig.cs
+14
-0
AgentRunLogForm.Designer.cs
Tools.Agent/Forms/AgentRunLogForm.Designer.cs
+333
-0
AgentRunLogForm.cs
Tools.Agent/Forms/AgentRunLogForm.cs
+382
-0
AgentRunLogForm.resx
Tools.Agent/Forms/AgentRunLogForm.resx
+71
-0
AgentSettingsForm.cs
Tools.Agent/Forms/AgentSettingsForm.cs
+104
-0
AgentRunDbReporter.cs
Tools.Agent/Support/AgentRunDbReporter.cs
+432
-0
AgentTelemetry.cs
Tools.Agent/Support/AgentTelemetry.cs
+9
-0
Tools.Agent.csproj
Tools.Agent/Tools.Agent.csproj
+10
-0
wMyAgent.cs
Tools.Agent/wMyAgent.cs
+5
-0
wExtend.cs
Tools/wExtend.cs
+1
-0
No files found.
AppHome/Tools.Agent.dll
View file @
2f8390cb
No preview for this file type
AppHome/Tools.Agent.xml
View file @
2f8390cb
This diff is collapsed.
Click to expand it.
Tools.Agent.Host/Program.cs
View file @
2f8390cb
...
@@ -190,7 +190,7 @@ namespace Tools.MyAgent.Host
...
@@ -190,7 +190,7 @@ namespace Tools.MyAgent.Host
private
sealed
class
LaunchOptions
private
sealed
class
LaunchOptions
{
{
public
string
Product
;
public
string
Product
;
public
string
User
=
"
访客"
;
public
string
User
=
"
"
;
// 启动参数 --user;默认空(未传 = 空串,展示层兜底"访客",上报记录原样透传)
public
string
ProjectRoot
=
""
;
public
string
ProjectRoot
=
""
;
public
string
KnowledgeBaseRoot
=
""
;
public
string
KnowledgeBaseRoot
=
""
;
public
string
KnowledgeBaseScope
=
""
;
public
string
KnowledgeBaseScope
=
""
;
...
...
Tools.Agent.ProbeRunDb/Program.cs
0 → 100644
View file @
2f8390cb
using
System
;
using
System.Collections.Generic
;
using
System.Data.SqlClient
;
using
System.IO
;
using
System.Text
;
using
System.Threading
;
using
System.Windows.Forms
;
using
Newtonsoft.Json.Linq
;
using
Tools.MyAgent
;
using
Tools.MyAgent.Config
;
using
Tools.MyAgent.Support
;
// 探针 4(2026-10-19):Agent日志回答区空白 —— RichEdit 真实渲染裁决
// STA 线程实例化 RichTextBox,用库里最新一条 AnswerText 走 BuildChatRtf 渲染,读回 .Text 验证解析结果
internal
static
class
Program
{
private
static
int
Main
()
{
Console
.
OutputEncoding
=
Encoding
.
UTF8
;
try
{
string
cfgPath
=
Path
.
GetFullPath
(
Path
.
Combine
(
AppDomain
.
CurrentDomain
.
BaseDirectory
,
@"..\..\..\AppHome\Agent\config\AgentConfig.json"
));
string
plain
=
SecretProtector
.
Unprotect
(
JObject
.
Parse
(
File
.
ReadAllText
(
cfgPath
)).
Value
<
string
>(
"RunDbConnection"
)
??
""
);
string
answer
=
null
;
using
(
var
conn
=
new
SqlConnection
(
plain
))
{
conn
.
Open
();
using
(
var
cmd
=
new
SqlCommand
(
"SELECT TOP 1 ISNULL(AnswerText, N'') FROM dbo.Agent_RunLog ORDER BY Id DESC"
,
conn
))
answer
=
Convert
.
ToString
(
cmd
.
ExecuteScalar
());
}
Console
.
WriteLine
(
"[1] DB AnswerText: len="
+
(
answer
==
null
?
-
1
:
answer
.
Length
));
int
textLen
=
-
1
;
string
shown
=
""
;
string
err
=
null
;
var
t
=
new
Thread
(()
=>
{
try
{
var
box
=
new
RichTextBox
{
Width
=
600
,
Height
=
400
};
var
handle
=
box
.
Handle
;
// 强制创建句柄
var
msg
=
new
ChatMessage
{
Role
=
"assistant"
,
Content
=
answer
};
string
rtf
=
MarkdownRenderer
.
BuildChatRtf
(
new
List
<
ChatMessage
>
{
msg
},
null
,
"助手"
,
"用户"
);
Console
.
WriteLine
(
"[2] RTF len="
+
rtf
.
Length
+
" hasHeader="
+
rtf
.
StartsWith
(
"{\\rtf1"
));
box
.
Rtf
=
rtf
;
textLen
=
box
.
Text
.
Length
;
shown
=
box
.
Text
;
}
catch
(
Exception
ex
)
{
err
=
ex
.
GetType
().
Name
+
": "
+
ex
.
Message
;
}
});
t
.
SetApartmentState
(
ApartmentState
.
STA
);
t
.
Start
();
t
.
Join
();
if
(
err
!=
null
)
{
Console
.
WriteLine
(
"[3] RENDER FAIL: "
+
err
);
return
2
;
}
Console
.
WriteLine
(
"[3] RichEdit 解析后 box.Text len="
+
textLen
+
" content=["
+
shown
+
"]"
);
Console
.
WriteLine
(
textLen
>
0
?
"PASS(渲染管线正常 ⇒ 窗口空白 = 运行的是旧 DLL 或别的断点)"
:
"FAIL(RichEdit 解析为空 ⇒ 渲染管线有真问题)"
);
return
textLen
>
0
?
0
:
3
;
}
catch
(
Exception
ex
)
{
Console
.
WriteLine
(
"FAIL: "
+
ex
.
Message
);
return
1
;
}
}
}
Tools.Agent.ProbeRunDb/Tools.Agent.ProbeRunDb.csproj
0 → 100644
View file @
2f8390cb
<?xml version="1.0" encoding="utf-8"?>
<Project
ToolsVersion=
"15.0"
xmlns=
"http://schemas.microsoft.com/developer/msbuild/2003"
>
<Import
Project=
"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition=
"Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"
/>
<PropertyGroup>
<Configuration
Condition=
" '$(Configuration)' == '' "
>
Debug
</Configuration>
<Platform
Condition=
" '$(Platform)' == '' "
>
AnyCPU
</Platform>
<ProjectGuid>
{A1B2C3D4-E5F6-4A7B-8C9D-0E1F2A3B4C5D}
</ProjectGuid>
<OutputType>
Exe
</OutputType>
<TargetFrameworkVersion>
v4.5
</TargetFrameworkVersion>
<LangVersion>
7.3
</LangVersion>
<OutputPath>
..\Tools.Agent\bin\Debug\
</OutputPath>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<DebugType>
full
</DebugType>
<Optimize>
false
</Optimize>
<DefineConstants>
DEBUG;TRACE
</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference
Include=
"System"
/>
<Reference
Include=
"System.Data"
/>
<Reference
Include=
"System.Core"
/>
<Reference
Include=
"System.Drawing"
/>
<Reference
Include=
"System.Windows.Forms"
/>
<Reference
Include=
"Newtonsoft.Json"
>
<HintPath>
..\Tools.Agent\bin\Debug\Newtonsoft.Json.dll
</HintPath>
</Reference>
<Reference
Include=
"Tools.Agent"
>
<HintPath>
..\Tools.Agent\bin\Debug\Tools.Agent.dll
</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile
Include=
"Program.cs"
/>
</ItemGroup>
<Import
Project=
"$(MSBuildToolsPath)\Microsoft.CSharp.targets"
/>
</Project>
Tools.Agent/Agent/AgentEngine.cs
View file @
2f8390cb
...
@@ -305,6 +305,7 @@ namespace Tools.MyAgent.Agent
...
@@ -305,6 +305,7 @@ namespace Tools.MyAgent.Agent
CostEstimator
.
Configure
(
cfg
.
CustomPrices
);
// R6 费用估算:应用自定义价格表覆盖
CostEstimator
.
Configure
(
cfg
.
CustomPrices
);
// R6 费用估算:应用自定义价格表覆盖
AgentTelemetry
.
Configure
(
cfg
.
TelemetryEnabled
,
cfg
.
ObservabilityLevel
);
// 可观测性开关与隐私级别
AgentTelemetry
.
Configure
(
cfg
.
TelemetryEnabled
,
cfg
.
ObservabilityLevel
);
// 可观测性开关与隐私级别
AgentRunDbReporter
.
ConfigureFromConfig
(
cfg
);
// 对话上报(agent_analysis_plan.md v1.3):连接串/表名随配置生效
// P0 连接串脱敏 / P3 工具权限:预存连接与角色规则随配置注入
// P0 连接串脱敏 / P3 工具权限:预存连接与角色规则随配置注入
DbConnections
=
cfg
.
DbConnections
??
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
DbConnections
=
cfg
.
DbConnections
??
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
_toolRoleAllow
=
cfg
.
ToolRoleAllow
??
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
_toolRoleAllow
=
cfg
.
ToolRoleAllow
??
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
...
@@ -360,6 +361,9 @@ namespace Tools.MyAgent.Agent
...
@@ -360,6 +361,9 @@ namespace Tools.MyAgent.Agent
if
(
_runScope
!=
null
)
if
(
_runScope
!=
null
)
{
{
_runScope
.
RunId
=
_diagnosticSessionId
;
_runScope
.
RunId
=
_diagnosticSessionId
;
_runScope
.
UserName
=
CurrentUser
??
""
;
// 启动参数 --user 原样透传(空 = 空串,展示层兜底不回写)
if
(!
string
.
IsNullOrEmpty
(
_currentQuestion
))
_runScope
.
QuestionText
=
_currentQuestion
;
// 仅内存([JsonIgnore]),DB 上报用
if
(
AgentTelemetry
.
IsDetailed
&&
!
string
.
IsNullOrEmpty
(
_currentQuestion
))
// §9:仅 detailed 存提问前 120 字
if
(
AgentTelemetry
.
IsDetailed
&&
!
string
.
IsNullOrEmpty
(
_currentQuestion
))
// §9:仅 detailed 存提问前 120 字
_runScope
.
QuestionPreview
=
_currentQuestion
.
Substring
(
0
,
Math
.
Min
(
120
,
_currentQuestion
.
Length
));
_runScope
.
QuestionPreview
=
_currentQuestion
.
Substring
(
0
,
Math
.
Min
(
120
,
_currentQuestion
.
Length
));
}
}
...
@@ -450,7 +454,12 @@ namespace Tools.MyAgent.Agent
...
@@ -450,7 +454,12 @@ namespace Tools.MyAgent.Agent
if
(!
IsDisposed
)
if
(!
IsDisposed
)
{
{
if
(
_runScope
!=
null
)
{
_runScope
.
ToolRounds
=
toolRounds
;
_runScope
.
AnswerKind
=
_answerKind
.
ToString
();
}
if
(
_runScope
!=
null
)
{
_runScope
.
ToolRounds
=
toolRounds
;
_runScope
.
AnswerKind
=
_answerKind
.
ToString
();
_runScope
.
AnswerText
=
finalAnswer
.
ToString
();
// 仅内存([JsonIgnore]),DB 上报用
}
AgentTelemetry
.
EndRun
(
_runScope
,
"success"
,
""
,
null
);
AgentTelemetry
.
EndRun
(
_runScope
,
"success"
,
""
,
null
);
OnComplete
?.
Invoke
();
OnComplete
?.
Invoke
();
if
(
_toolTrace
.
Count
>
0
)
if
(
_toolTrace
.
Count
>
0
)
...
...
Tools.Agent/AgentRuntime.cs
View file @
2f8390cb
...
@@ -15,8 +15,8 @@ namespace Tools.MyAgent
...
@@ -15,8 +15,8 @@ namespace Tools.MyAgent
/// <summary>配置、历史、索引、日志和输出的根目录。空值使用应用目录下的 Agent。</summary>
/// <summary>配置、历史、索引、日志和输出的根目录。空值使用应用目录下的 Agent。</summary>
public
string
DataRoot
{
get
;
set
;
}
public
string
DataRoot
{
get
;
set
;
}
/// <summary>当前用户或角色,用于聊天展示、工具权限
和数据库审计
。</summary>
/// <summary>当前用户或角色,用于聊天展示、工具权限
、数据库审计与对话上报记录。默认空(宿主未传即空串,展示层自行兜底"访客")
。</summary>
public
string
CurrentUser
{
get
;
set
;
}
=
"
访客
"
;
public
string
CurrentUser
{
get
;
set
;
}
=
""
;
/// <summary>宿主注入的诊断根目录;为空时由产品上下文 ProjectRoot 自动生成 source 根。</summary>
/// <summary>宿主注入的诊断根目录;为空时由产品上下文 ProjectRoot 自动生成 source 根。</summary>
public
IReadOnlyList
<
DiagnosticRoot
>
DiagnosticRoots
{
get
;
set
;
}
public
IReadOnlyList
<
DiagnosticRoot
>
DiagnosticRoots
{
get
;
set
;
}
...
@@ -106,6 +106,34 @@ namespace Tools.MyAgent
...
@@ -106,6 +106,34 @@ namespace Tools.MyAgent
return
new
Tools
.
MyAgent
.
Forms
.
AgentAdminForm
(
null
,
days
,
allowDetailed
,
autoRefresh
);
return
new
Tools
.
MyAgent
.
Forms
.
AgentAdminForm
(
null
,
days
,
allowDetailed
,
autoRefresh
);
}
}
/// <summary>
/// 创建 Agent 日志查看窗体(agent_analysis_plan.md v1.3 / Q5 决议):只读查询对话上报记录。
/// <para>由宿主"实施工具"菜单直接打开;连接串/表名由宿主从 AgentConfig 读出传入(窗口自身不读配置文件)。
/// 连接串为空时仍返回窗体(查询时报错提示未配置)。</para>
/// </summary>
public
Form
CreateRunLogForm
(
string
connection
,
string
table
=
"Agent_RunLog"
)
{
return
new
Tools
.
MyAgent
.
Forms
.
AgentRunLogForm
(
connection
,
table
);
}
/// <summary>
/// 读取本机默认位置(<程序目录>/Agent/config/AgentConfig.json)的 Agent 配置,
/// RunDbConnection 已解密为明文。供无上下文的工具模块(Activator 无参创建)自取上报配置;失败返回 null。
/// </summary>
public
static
Config
.
AgentConfig
TryLoadLocalConfig
()
{
try
{
string
path
=
Path
.
Combine
(
AppDomain
.
CurrentDomain
.
BaseDirectory
,
"Agent"
,
"config"
,
"AgentConfig.json"
);
if
(!
File
.
Exists
(
path
))
return
null
;
var
cfg
=
Newtonsoft
.
Json
.
JsonConvert
.
DeserializeObject
<
Config
.
AgentConfig
>(
File
.
ReadAllText
(
path
,
System
.
Text
.
Encoding
.
UTF8
));
if
(
cfg
!=
null
)
cfg
.
RunDbConnection
=
Config
.
SecretProtector
.
Unprotect
(
cfg
.
RunDbConnection
);
return
cfg
;
}
catch
{
return
null
;
}
}
private
void
EnsureDefaultResources
()
private
void
EnsureDefaultResources
()
{
{
Directory
.
CreateDirectory
(
DataRoot
);
Directory
.
CreateDirectory
(
DataRoot
);
...
...
Tools.Agent/Config/AgentConfig.cs
View file @
2f8390cb
...
@@ -222,5 +222,19 @@
...
@@ -222,5 +222,19 @@
/// <summary>看板 30s 自动刷新(默认关闭,避免常驻定时器拖住宿主)。</summary>
/// <summary>看板 30s 自动刷新(默认关闭,避免常驻定时器拖住宿主)。</summary>
public
bool
AdminAutoRefresh
{
get
;
set
;
}
=
false
;
public
bool
AdminAutoRefresh
{
get
;
set
;
}
=
false
;
// ══════════════ 高级项:对话上报(每轮一条记录落 SQL Server,供统计分析;见 agent_analysis_plan.md v1.3) ══════════════
/// <summary>对话上报总开关;关闭则不订阅 OnRunCompleted、不连库。</summary>
public
bool
RunDbEnabled
{
get
;
set
;
}
=
false
;
/// <summary>
/// SQL Server 连接串(库由连接串决定,缺表自动创建 Agent_RunLog)。
/// <para>落盘时经 DPAPI 加密(见 SecretProtector),内存中为明文;设置页「高级 → 对话上报」可配置。</para>
/// </summary>
public
string
RunDbConnection
{
get
;
set
;
}
=
""
;
/// <summary>上报目标表名(仅允许字母/数字/下划线,防注入;建表与 INSERT 均使用该名)。</summary>
public
string
RunDbTable
{
get
;
set
;
}
=
"Agent_RunLog"
;
}
}
}
}
Tools.Agent/Forms/AgentRunLogForm.Designer.cs
0 → 100644
View file @
2f8390cb
This diff is collapsed.
Click to expand it.
Tools.Agent/Forms/AgentRunLogForm.cs
0 → 100644
View file @
2f8390cb
This diff is collapsed.
Click to expand it.
Tools.Agent/Forms/AgentRunLogForm.resx
0 → 100644
View file @
2f8390cb
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
-->
<xsd:schema
id=
"root"
xmlns=
""
xmlns:xsd=
"http://www.w3.org/2001/XMLSchema"
xmlns:msdata=
"urn:schemas-microsoft-com:xml-msdata"
>
<xsd:import
namespace=
"http://www.w3.org/XML/1998/namespace"
/>
<xsd:element
name=
"root"
msdata:IsDataSet=
"true"
>
<xsd:complexType>
<xsd:choice
maxOccurs=
"unbounded"
>
<xsd:element
name=
"metadata"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"type"
type=
"xsd:string"
/>
<xsd:attribute
name=
"mimetype"
type=
"xsd:string"
/>
<xsd:attribute
ref=
"xml:space"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"assembly"
>
<xsd:complexType>
<xsd:attribute
name=
"alias"
type=
"xsd:string"
/>
<xsd:attribute
name=
"name"
type=
"xsd:string"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"data"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"1"
/>
<xsd:element
name=
"comment"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"2"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
msdata:Ordinal=
"1"
/>
<xsd:attribute
name=
"type"
type=
"xsd:string"
msdata:Ordinal=
"3"
/>
<xsd:attribute
name=
"mimetype"
type=
"xsd:string"
msdata:Ordinal=
"4"
/>
<xsd:attribute
ref=
"xml:space"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"resheader"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"1"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader
name=
"resmimetype"
>
<value>
text/microsoft-resx
</value>
</resheader>
<resheader
name=
"version"
>
<value>
2.0
</value>
</resheader>
<resheader
name=
"reader"
>
<value>
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader
name=
"writer"
>
<value>
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>
Tools.Agent/Forms/AgentSettingsForm.cs
View file @
2f8390cb
...
@@ -122,6 +122,7 @@ namespace Tools.MyAgent.Forms
...
@@ -122,6 +122,7 @@ namespace Tools.MyAgent.Forms
BuildToolPermissionUi
();
// P3:工具级权限(按角色)输入区
BuildToolPermissionUi
();
// P3:工具级权限(按角色)输入区
BuildDashboardTab
();
// 可观测性:统计看板入口(替代隐晦的 /admin)
BuildDashboardTab
();
// 可观测性:统计看板入口(替代隐晦的 /admin)
BuildRemoteKbUi
();
// v4.1:远程知识库条目接口(高级 → 语义检索页底部)
BuildRemoteKbUi
();
// v4.1:远程知识库条目接口(高级 → 语义检索页底部)
BuildRunDbTab
();
// 对话上报(agent_analysis_plan.md v1.3):高级 → 二级 Tab「对话上报」
// 回答形态不再提供设置页(v1.2):全部内部默认(见 AgentConfig 注释),降低设置页认知负担
// 回答形态不再提供设置页(v1.2):全部内部默认(见 AgentConfig 注释),降低设置页认知负担
BindConfig
();
// 配置值回填控件(控件创建见 Designer.cs)
BindConfig
();
// 配置值回填控件(控件创建见 Designer.cs)
ApplyProviderMode
();
// 布局联动:BaseUrl 行显隐
ApplyProviderMode
();
// 布局联动:BaseUrl 行显隐
...
@@ -210,6 +211,100 @@ namespace Tools.MyAgent.Forms
...
@@ -210,6 +211,100 @@ namespace Tools.MyAgent.Forms
tabMain
.
TabPages
.
Add
(
tabDb
);
tabMain
.
TabPages
.
Add
(
tabDb
);
}
}
// ══ 对话上报(agent_analysis_plan.md v1.3):高级 → 二级 Tab「对话上报」(程序化创建,避免侵入设计器) ══
private
CheckBox
chkRunDbEnabled
;
private
TextBox
txtRunDbConn
;
private
TextBox
txtRunDbTable
;
private
Button
btnTestRunDb
;
/// <summary>
/// 高级配置新增二级 Tab「对话上报」:每轮对话完成后自动上报一条记录到 SQL Server
/// (库由连接串决定,缺表自动创建 Agent_RunLog;cancel 不上报;提问/回答原文恒落库)。
/// </summary>
private
void
BuildRunDbTab
()
{
var
tabRunDb
=
new
TabPage
{
Text
=
"对话上报"
,
Padding
=
new
Padding
(
3
)
};
chkRunDbEnabled
=
new
CheckBox
{
Text
=
"启用对话上报(每轮对话完成后写入一条运行记录,客户取消的轮次不记录)"
,
Location
=
new
Point
(
12
,
12
),
AutoSize
=
true
,
};
var
lblConn
=
new
Label
{
Text
=
"SQL Server 连接串(库由连接串决定;保存后加密存储)"
,
Location
=
new
Point
(
12
,
40
),
AutoSize
=
true
};
txtRunDbConn
=
new
TextBox
{
Location
=
new
Point
(
12
,
62
),
Size
=
new
Size
(
556
,
46
),
Multiline
=
true
,
Font
=
new
Font
(
"Consolas"
,
9F
),
};
var
lblTable
=
new
Label
{
Text
=
"目标表名(缺表自动创建;仅字母/数字/下划线)"
,
Location
=
new
Point
(
12
,
116
),
AutoSize
=
true
};
txtRunDbTable
=
new
TextBox
{
Location
=
new
Point
(
12
,
138
),
Size
=
new
Size
(
240
,
23
),
Text
=
"Agent_RunLog"
,
Font
=
new
Font
(
"Consolas"
,
9F
),
};
btnTestRunDb
=
new
Button
{
Text
=
"测试连接"
,
Location
=
new
Point
(
268
,
136
),
Size
=
new
Size
(
96
,
26
),
};
btnTestRunDb
.
Click
+=
new
EventHandler
(
OnTestRunDb
);
var
hint
=
new
Label
{
Text
=
"提问与回答原文会存入该库,用于统计分析与体验优化。查看入口:实施工具 → Agent日志。\r\n示例:Server=主机;Database=库名;User Id=账号;Password=密码;Trusted_Connection=False"
,
Location
=
new
Point
(
12
,
172
),
AutoSize
=
false
,
Size
=
new
Size
(
556
,
40
),
ForeColor
=
Color
.
Gray
,
};
tabRunDb
.
Controls
.
Add
(
chkRunDbEnabled
);
tabRunDb
.
Controls
.
Add
(
lblConn
);
tabRunDb
.
Controls
.
Add
(
txtRunDbConn
);
tabRunDb
.
Controls
.
Add
(
lblTable
);
tabRunDb
.
Controls
.
Add
(
txtRunDbTable
);
tabRunDb
.
Controls
.
Add
(
btnTestRunDb
);
tabRunDb
.
Controls
.
Add
(
hint
);
tabAdvSub
.
TabPages
.
Add
(
tabRunDb
);
}
/// <summary>测试连接:Open + SELECT 1,成功再预演建表(无建表权限时提示具体错误,不落任何数据)。</summary>
private
void
OnTestRunDb
(
object
sender
,
EventArgs
e
)
{
try
{
string
conn
=
txtRunDbConn
.
Text
.
Trim
();
if
(
conn
.
Length
==
0
)
{
AgentUtils
.
Toast
(
"请先填写连接串"
);
return
;
}
string
table
=
string
.
IsNullOrWhiteSpace
(
txtRunDbTable
.
Text
)
?
"Agent_RunLog"
:
txtRunDbTable
.
Text
.
Trim
();
// 建表预演:复用 Reporter 的幂等建表(表已存在 = 无副作用;返回错误消息而非抛异常)
string
error
=
AgentRunDbReporter
.
EnsureTableForTest
(
conn
,
table
);
if
(
error
==
null
)
{
// 2026-10-19 真机踩坑:连接串/表名已保存但「启用对话上报」未勾选 ⇒ 表里永远无记录(测试连接与开关无关)
if
(!
chkRunDbEnabled
.
Checked
)
AgentUtils
.
Toast
(
"连接成功,表已就绪:"
+
table
+
"\n⚠ 但「启用对话上报」未勾选,上报不会生效!"
,
6000
);
else
AgentUtils
.
Toast
(
"连接成功,建表/表已就绪:"
+
table
,
3000
);
}
else
AgentUtils
.
Toast
(
"连接失败:"
+
error
,
5000
);
}
catch
(
Exception
ex
)
{
AgentUtils
.
Toast
(
"连接失败:"
+
ex
.
Message
,
5000
);
}
}
// ══ P3:工具级权限(按角色) ══
// ══ P3:工具级权限(按角色) ══
private
TextBox
txtToolRoles
;
private
TextBox
txtToolRoles
;
...
@@ -493,6 +588,11 @@ namespace Tools.MyAgent.Forms
...
@@ -493,6 +588,11 @@ namespace Tools.MyAgent.Forms
cmbEmbModel
.
Text
=
_config
.
EmbeddingModel
;
cmbEmbModel
.
Text
=
_config
.
EmbeddingModel
;
txtEmbKey
.
Text
=
_config
.
EmbeddingApiKey
;
txtEmbKey
.
Text
=
_config
.
EmbeddingApiKey
;
// 高级配置:对话上报(agent_analysis_plan.md v1.3)
chkRunDbEnabled
.
Checked
=
_config
.
RunDbEnabled
;
txtRunDbConn
.
Text
=
_config
.
RunDbConnection
??
""
;
// LoadConfig 已解密为明文
txtRunDbTable
.
Text
=
string
.
IsNullOrWhiteSpace
(
_config
.
RunDbTable
)
?
"Agent_RunLog"
:
_config
.
RunDbTable
;
// 远程知识库(v4.1):URL 模板逐行回填
// 远程知识库(v4.1):URL 模板逐行回填
txtRemoteKb
.
Text
=
string
.
Join
(
Environment
.
NewLine
,
_config
.
RemoteKbEntries
??
new
List
<
string
>());
txtRemoteKb
.
Text
=
string
.
Join
(
Environment
.
NewLine
,
_config
.
RemoteKbEntries
??
new
List
<
string
>());
...
@@ -955,6 +1055,10 @@ namespace Tools.MyAgent.Forms
...
@@ -955,6 +1055,10 @@ namespace Tools.MyAgent.Forms
_config
.
EmbeddingBaseUrl
=
txtEmbUrl
.
Text
.
Trim
();
_config
.
EmbeddingBaseUrl
=
txtEmbUrl
.
Text
.
Trim
();
_config
.
EmbeddingModel
=
string
.
IsNullOrEmpty
(
cmbEmbModel
.
Text
.
Trim
())
?
"bge-m3"
:
cmbEmbModel
.
Text
.
Trim
();
_config
.
EmbeddingModel
=
string
.
IsNullOrEmpty
(
cmbEmbModel
.
Text
.
Trim
())
?
"bge-m3"
:
cmbEmbModel
.
Text
.
Trim
();
_config
.
EmbeddingApiKey
=
txtEmbKey
.
Text
.
Trim
();
_config
.
EmbeddingApiKey
=
txtEmbKey
.
Text
.
Trim
();
// 高级配置:对话上报(agent_analysis_plan.md v1.3;连接串加密由 wMyAgent.SaveAgentConfig 投影层处理)
_config
.
RunDbEnabled
=
chkRunDbEnabled
.
Checked
;
_config
.
RunDbConnection
=
txtRunDbConn
.
Text
.
Trim
();
_config
.
RunDbTable
=
string
.
IsNullOrWhiteSpace
(
txtRunDbTable
.
Text
)
?
"Agent_RunLog"
:
txtRunDbTable
.
Text
.
Trim
();
// 远程知识库(v4.1):每行一条 URL 模板,空行忽略
// 远程知识库(v4.1):每行一条 URL 模板,空行忽略
_config
.
RemoteKbEntries
=
(
txtRemoteKb
!=
null
?
txtRemoteKb
.
Lines
:
new
string
[
0
])
_config
.
RemoteKbEntries
=
(
txtRemoteKb
!=
null
?
txtRemoteKb
.
Lines
:
new
string
[
0
])
.
Select
(
l
=>
(
l
??
""
).
Trim
())
.
Select
(
l
=>
(
l
??
""
).
Trim
())
...
...
Tools.Agent/Support/AgentRunDbReporter.cs
0 → 100644
View file @
2f8390cb
This diff is collapsed.
Click to expand it.
Tools.Agent/Support/AgentTelemetry.cs
View file @
2f8390cb
...
@@ -39,6 +39,15 @@ namespace Tools.MyAgent
...
@@ -39,6 +39,15 @@ namespace Tools.MyAgent
/// <summary>提问前 120 字(仅 detailed 级别填充;basic 恒空 —— §9 隐私分级)。</summary>
/// <summary>提问前 120 字(仅 detailed 级别填充;basic 恒空 —— §9 隐私分级)。</summary>
public
string
QuestionPreview
=
""
;
public
string
QuestionPreview
=
""
;
/// <summary>提问原文(仅内存,[JsonIgnore] 不进 jsonl —— 供 DB 上报用,落库由 AgentRunDbReporter 决定)。</summary>
[
JsonIgnore
]
public
string
QuestionText
=
""
;
/// <summary>回答原文(仅内存,[JsonIgnore] 不进 jsonl;success 路径由引擎填充,cancel/error 留空)。</summary>
[
JsonIgnore
]
public
string
AnswerText
=
""
;
/// <summary>当前用户(启动参数 --user 原样透传;仅内存,[JsonIgnore] 不进 jsonl,落库列 UserName)。</summary>
[
JsonIgnore
]
public
string
UserName
=
""
;
/// <summary>配置模型。</summary>
/// <summary>配置模型。</summary>
public
string
Model
=
""
;
public
string
Model
=
""
;
...
...
Tools.Agent/Tools.Agent.csproj
View file @
2f8390cb
...
@@ -122,6 +122,7 @@
...
@@ -122,6 +122,7 @@
<Compile
Include=
"Config\AgentConfig.cs"
/>
<Compile
Include=
"Config\AgentConfig.cs"
/>
<Compile
Include=
"Config\RoleTemplateStore.cs"
/>
<Compile
Include=
"Config\RoleTemplateStore.cs"
/>
<Compile
Include=
"Config\SecretProtector.cs"
/>
<Compile
Include=
"Config\SecretProtector.cs"
/>
<Compile
Include=
"Support\AgentRunDbReporter.cs"
/>
<Compile
Include=
"Forms\AgentAdminForm.cs"
>
<Compile
Include=
"Forms\AgentAdminForm.cs"
>
<SubType>
Form
</SubType>
<SubType>
Form
</SubType>
</Compile>
</Compile>
...
@@ -140,6 +141,12 @@
...
@@ -140,6 +141,12 @@
<Compile
Include=
"Forms\AgentSettingsForm.Designer.cs"
>
<Compile
Include=
"Forms\AgentSettingsForm.Designer.cs"
>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
</Compile>
</Compile>
<Compile
Include=
"Forms\AgentRunLogForm.cs"
>
<SubType>
Form
</SubType>
</Compile>
<Compile
Include=
"Forms\AgentRunLogForm.Designer.cs"
>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
</Compile>
<Compile
Include=
"Forms\DocLineViewer.cs"
>
<Compile
Include=
"Forms\DocLineViewer.cs"
>
<SubType>
Form
</SubType>
<SubType>
Form
</SubType>
</Compile>
</Compile>
...
@@ -187,6 +194,9 @@
...
@@ -187,6 +194,9 @@
<EmbeddedResource
Include=
"Forms\AgentHistoryForm.resx"
>
<EmbeddedResource
Include=
"Forms\AgentHistoryForm.resx"
>
<DependentUpon>
AgentHistoryForm.cs
</DependentUpon>
<DependentUpon>
AgentHistoryForm.cs
</DependentUpon>
</EmbeddedResource>
</EmbeddedResource>
<EmbeddedResource
Include=
"Forms\AgentRunLogForm.resx"
>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
</EmbeddedResource>
<EmbeddedResource
Include=
"Forms\AgentSettingsForm.resx"
>
<EmbeddedResource
Include=
"Forms\AgentSettingsForm.resx"
>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
</EmbeddedResource>
</EmbeddedResource>
...
...
Tools.Agent/wMyAgent.cs
View file @
2f8390cb
...
@@ -307,6 +307,7 @@ namespace Tools.MyAgent
...
@@ -307,6 +307,7 @@ namespace Tools.MyAgent
cfg
.
ApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
ApiKey
);
cfg
.
ApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
ApiKey
);
cfg
.
EmbeddingApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
EmbeddingApiKey
);
cfg
.
EmbeddingApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
EmbeddingApiKey
);
cfg
.
BackupApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
BackupApiKey
);
cfg
.
BackupApiKey
=
SecretProtector
.
Unprotect
(
cfg
.
BackupApiKey
);
cfg
.
RunDbConnection
=
SecretProtector
.
Unprotect
(
cfg
.
RunDbConnection
);
// 对话上报连接串(DPAPI 落盘)
if
(
cfg
.
DbConnections
!=
null
)
if
(
cfg
.
DbConnections
!=
null
)
{
{
var
plain
=
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
var
plain
=
new
Dictionary
<
string
,
string
>(
StringComparer
.
OrdinalIgnoreCase
);
...
@@ -401,6 +402,10 @@ namespace Tools.MyAgent
...
@@ -401,6 +402,10 @@ namespace Tools.MyAgent
AdminRoles
=
cfg
.
AdminRoles
,
AdminRoles
=
cfg
.
AdminRoles
,
DashboardDays
=
cfg
.
DashboardDays
,
DashboardDays
=
cfg
.
DashboardDays
,
AdminAutoRefresh
=
cfg
.
AdminAutoRefresh
,
AdminAutoRefresh
=
cfg
.
AdminAutoRefresh
,
// 对话上报(agent_analysis_plan.md v1.3;漏登记 ⇒ 设置页保存一次即被静默清空)
RunDbEnabled
=
cfg
.
RunDbEnabled
,
RunDbConnection
=
SecretProtector
.
Protect
(
cfg
.
RunDbConnection
),
RunDbTable
=
cfg
.
RunDbTable
,
};
};
File
.
WriteAllText
(
AgentConfigFilePath
,
Newtonsoft
.
Json
.
JsonConvert
.
SerializeObject
(
toSave
),
System
.
Text
.
Encoding
.
UTF8
);
File
.
WriteAllText
(
AgentConfigFilePath
,
Newtonsoft
.
Json
.
JsonConvert
.
SerializeObject
(
toSave
),
System
.
Text
.
Encoding
.
UTF8
);
}
}
...
...
Tools/wExtend.cs
View file @
2f8390cb
...
@@ -49,6 +49,7 @@ namespace Tools
...
@@ -49,6 +49,7 @@ namespace Tools
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wEmptyTable
),
"清空表"
,
"tr:输入主表、自动清空关联表的工具"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wEmptyTable
),
"清空表"
,
"tr:输入主表、自动清空关联表的工具"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wExcelExportSetting
),
"Excel导出设置"
,
"tr:Excel导出配置图形化版本"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wExcelExportSetting
),
"Excel导出设置"
,
"tr:Excel导出配置图形化版本"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wLogViewer
),
"日志查看器"
,
"tr:可以方便的查看系统日志"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wLogViewer
),
"日志查看器"
,
"tr:可以方便的查看系统日志"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
Tools
.
MyAgent
.
Forms
.
AgentRunLogForm
),
"Agent日志"
,
"tr:查看AI对话上报记录(按用户提问统计分析)"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wTextFormatter
),
"格式化工具"
,
"tr:SQL和JSON文本格式化工具"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wTextFormatter
),
"格式化工具"
,
"tr:SQL和JSON文本格式化工具"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wTextDiff
),
"文本对比工具"
,
"tr:行级文本差异对比,支持左右/上下布局"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
UI
.
wTextDiff
),
"文本对比工具"
,
"tr:行级文本差异对比,支持左右/上下布局"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
DotNetVersionChecker
.
FrmVersion
),
"系统检测"
,
"lxj:检测操作系统运行环境"
),
this
.
CreateModule
(
Tools_imp
,
typeof
(
DotNetVersionChecker
.
FrmVersion
),
"系统检测"
,
"lxj:检测操作系统运行环境"
),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment