Commit ad2f9bb4 authored by 段廷瑞's avatar 段廷瑞

pref: 生成参数微调,可选能力默认启用

parent 6a91399b
...@@ -70,3 +70,4 @@ bin ...@@ -70,3 +70,4 @@ bin
!/AppHome/Agent/industry/ !/AppHome/Agent/industry/
/AppHome/Agent/config/AgentConfig.json /AppHome/Agent/config/AgentConfig.json
/cc /cc
/AppHome/Logs
...@@ -4,6 +4,8 @@ using System.Collections.Generic; ...@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using Tools.MyAgent; using Tools.MyAgent;
using Tools.MyAgent.Agent; using Tools.MyAgent.Agent;
using Tools.MyAgent.Agent.Tools;
using Tools.MyAgent.Config;
using Tools.MyAgent.Kb; using Tools.MyAgent.Kb;
namespace AgentTest namespace AgentTest
...@@ -27,6 +29,27 @@ namespace AgentTest ...@@ -27,6 +29,27 @@ namespace AgentTest
Assert.Equal(0, errorCount, "释放后的迟到请求不应再向 UI 上报网络错误"); Assert.Equal(0, errorCount, "释放后的迟到请求不应再向 UI 上报网络错误");
} }
[Test]
public void DefaultConfig_UsesExpandedGenerationDefaults_AndOptionalTools()
{
var cfg = new AgentConfig();
Assert.Equal(32768, cfg.MaxTokens, "默认输出上限应为原默认值的 4 倍");
Assert.Equal(128000, cfg.MaxContextTokens, "默认上下文预算应为原默认值的 4 倍");
Assert.True(cfg.EnableOptionalTools, "可选能力默认应启用");
}
[Test]
public void DefaultToolSchema_IncludesOptionalTools()
{
var tools = ToolSchema.Build();
string schema = tools.ToString();
Assert.Contains(schema, "db_query", "默认工具应包含数据库查询");
Assert.Contains(schema, "db_schema", "默认工具应包含数据库结构查询");
Assert.Contains(schema, "doc_export", "默认工具应包含文档导出");
}
// ── token 估算 ── // ── token 估算 ──
[Test] [Test]
......
No preview for this file type
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
</summary> </summary>
</member> </member>
<member name="F:Tools.MyAgent.Agent.AgentEngine._contextTokens"> <member name="F:Tools.MyAgent.Agent.AgentEngine._contextTokens">
<summary>上下文 token 预算(由配置注入;默认 32000)</summary> <summary>上下文 token 预算(由配置注入;默认 128000)</summary>
</member> </member>
<member name="F:Tools.MyAgent.Agent.AgentEngine.MaxToolReturnChars"> <member name="F:Tools.MyAgent.Agent.AgentEngine.MaxToolReturnChars">
<summary>工具结果回填模型的字符上限(#42:超限压缩 + 完整结果落盘)。 <summary>工具结果回填模型的字符上限(#42:超限压缩 + 完整结果落盘)。
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
<summary>本次运行已自动续写的轮数(每次 RunAsync 重置;见 FinishAnswerAsync)</summary> <summary>本次运行已自动续写的轮数(每次 RunAsync 重置;见 FinishAnswerAsync)</summary>
</member> </member>
<member name="F:Tools.MyAgent.Agent.AgentEngine._includeOptionalTools"> <member name="F:Tools.MyAgent.Agent.AgentEngine._includeOptionalTools">
<summary>是否向模型下发可选/高级工具(默认只下发核心工具)</summary> <summary>是否向模型下发可选/高级工具(默认下发全部已注册工具)</summary>
</member> </member>
<member name="F:Tools.MyAgent.Agent.AgentEngine._toolRoleAllow"> <member name="F:Tools.MyAgent.Agent.AgentEngine._toolRoleAllow">
<summary>工具级权限(P3):工具名 → 允许角色列表;空 = 全部可用(由 AgentConfig.ToolRoleAllow 注入)</summary> <summary>工具级权限(P3):工具名 → 允许角色列表;空 = 全部可用(由 AgentConfig.ToolRoleAllow 注入)</summary>
...@@ -495,7 +495,7 @@ ...@@ -495,7 +495,7 @@
</summary> </summary>
</member> </member>
<member name="M:Tools.MyAgent.Agent.ToolSchema.Build"> <member name="M:Tools.MyAgent.Agent.ToolSchema.Build">
<summary>构建默认工具(核心能力)的 JSON Schema</summary> <summary>构建默认工具(包含可选能力)的 JSON Schema</summary>
</member> </member>
<member name="M:Tools.MyAgent.Agent.ToolSchema.Build(System.Boolean,System.Func{System.String,System.Boolean})"> <member name="M:Tools.MyAgent.Agent.ToolSchema.Build(System.Boolean,System.Func{System.String,System.Boolean})">
<summary> <summary>
...@@ -720,7 +720,7 @@ ...@@ -720,7 +720,7 @@
<summary>故障转移(#31):备用模型配置;EnableFailover 且主模型连续失败达阈值时自动切换</summary> <summary>故障转移(#31):备用模型配置;EnableFailover 且主模型连续失败达阈值时自动切换</summary>
</member> </member>
<member name="P:Tools.MyAgent.Config.AgentConfig.EnableOptionalTools"> <member name="P:Tools.MyAgent.Config.AgentConfig.EnableOptionalTools">
<summary>是否启用可选/高级工具(db_query、module_patch、img_search、/workflow)</summary> <summary>是否启用可选/高级工具(db_query、module_patch、img_search、/workflow);默认启用,可显式关闭</summary>
</member> </member>
<member name="P:Tools.MyAgent.Config.AgentConfig.EnableImageInput"> <member name="P:Tools.MyAgent.Config.AgentConfig.EnableImageInput">
<summary>是否启用图片提问(多模态,v2.2):启用后粘贴截图随提问以 image_url 发送,需视觉模型支持(如 DeepSeek-VL / qwen-vl);默认启用</summary> <summary>是否启用图片提问(多模态,v2.2):启用后粘贴截图随提问以 image_url 发送,需视觉模型支持(如 DeepSeek-VL / qwen-vl);默认启用</summary>
...@@ -1206,7 +1206,7 @@ ...@@ -1206,7 +1206,7 @@
</summary> </summary>
</member> </member>
<member name="M:Tools.MyAgent.Kb.KbIndex.Start"> <member name="M:Tools.MyAgent.Kb.KbIndex.Start">
<summary>启动:打开/建库 + 后台构建(幂等)</summary> <summary>启动索引:只在后台打开 SQLite 并开始构建,调用方不会被建库 IO 阻塞。</summary>
</member> </member>
<member name="M:Tools.MyAgent.Kb.KbIndex.Invalidate"> <member name="M:Tools.MyAgent.Kb.KbIndex.Invalidate">
<summary>标记变更,调度后台增量重建(带去抖;构建中则完成后自动续跑)</summary> <summary>标记变更,调度后台增量重建(带去抖;构建中则完成后自动续跑)</summary>
...@@ -1357,6 +1357,11 @@ ...@@ -1357,6 +1357,11 @@
<member name="P:Tools.MyAgent.Kb.KbService.IsSearchValid"> <member name="P:Tools.MyAgent.Kb.KbService.IsSearchValid">
<summary>搜索范围是否有效(目录存在)</summary> <summary>搜索范围是否有效(目录存在)</summary>
</member> </member>
<member name="M:Tools.MyAgent.Kb.KbService.EnsureIndexStartedIfSmall(System.Int32)">
<summary>
仅为小型知识库自动启动索引。文件数未知或超过阈值时保持未建索引,避免打开窗口触发大规模 SQLite 建库。
</summary>
</member>
<member name="M:Tools.MyAgent.Kb.KbService.EnsureIndexStarted"> <member name="M:Tools.MyAgent.Kb.KbService.EnsureIndexStarted">
<summary> <summary>
启动后台检索索引(幂等):索引目录固定为输出目录下 index 文件夹,与所选知识库无关。 启动后台检索索引(幂等):索引目录固定为输出目录下 index 文件夹,与所选知识库无关。
......
...@@ -28,8 +28,8 @@ namespace Tools.MyAgent.Agent ...@@ -28,8 +28,8 @@ namespace Tools.MyAgent.Agent
private CancellationTokenSource _cts; private CancellationTokenSource _cts;
private int _disposeStarted; private int _disposeStarted;
/// <summary>上下文 token 预算(由配置注入;默认 32000)</summary> /// <summary>上下文 token 预算(由配置注入;默认 128000)</summary>
private int _contextTokens = 32000; private int _contextTokens = AgentConfig.DefaultMaxContextTokens;
// #31 故障转移 // #31 故障转移
private FailoverPolicy _failover; private FailoverPolicy _failover;
...@@ -107,8 +107,8 @@ namespace Tools.MyAgent.Agent ...@@ -107,8 +107,8 @@ namespace Tools.MyAgent.Agent
/// <summary>本次运行已自动续写的轮数(每次 RunAsync 重置;见 FinishAnswerAsync)</summary> /// <summary>本次运行已自动续写的轮数(每次 RunAsync 重置;见 FinishAnswerAsync)</summary>
private int _continueRounds; private int _continueRounds;
/// <summary>是否向模型下发可选/高级工具(默认只下发核心工具)</summary> /// <summary>是否向模型下发可选/高级工具(默认下发全部已注册工具)</summary>
private bool _includeOptionalTools; private bool _includeOptionalTools = true;
/// <summary>工具级权限(P3):工具名 → 允许角色列表;空 = 全部可用(由 AgentConfig.ToolRoleAllow 注入)</summary> /// <summary>工具级权限(P3):工具名 → 允许角色列表;空 = 全部可用(由 AgentConfig.ToolRoleAllow 注入)</summary>
private Dictionary<string, string> _toolRoleAllow = new Dictionary<string, string>(); private Dictionary<string, string> _toolRoleAllow = new Dictionary<string, string>();
...@@ -194,8 +194,8 @@ namespace Tools.MyAgent.Agent ...@@ -194,8 +194,8 @@ namespace Tools.MyAgent.Agent
_client.ApiKey = cfg.ApiKey ?? ""; _client.ApiKey = cfg.ApiKey ?? "";
_client.Model = string.IsNullOrEmpty(cfg.Model) ? "deepseek-v4-flash" : cfg.Model; _client.Model = string.IsNullOrEmpty(cfg.Model) ? "deepseek-v4-flash" : cfg.Model;
_client.Temperature = cfg.Temperature; _client.Temperature = cfg.Temperature;
_client.MaxTokens = cfg.MaxTokens > 0 ? cfg.MaxTokens : 8192; _client.MaxTokens = cfg.MaxTokens > 0 ? cfg.MaxTokens : AgentConfig.DefaultMaxTokens;
_contextTokens = cfg.MaxContextTokens > 0 ? cfg.MaxContextTokens : 32000; _contextTokens = cfg.MaxContextTokens > 0 ? cfg.MaxContextTokens : AgentConfig.DefaultMaxContextTokens;
// R12:策略参数(越界回退默认,防止手改配置文件导致异常行为) // R12:策略参数(越界回退默认,防止手改配置文件导致异常行为)
_maxToolRounds = ClampStrategy(cfg.MaxToolRounds, 1, 50, 15); _maxToolRounds = ClampStrategy(cfg.MaxToolRounds, 1, 50, 15);
_maxHistoryMessages = ClampStrategy(cfg.MaxHistoryMessages, 3, 200, 60); _maxHistoryMessages = ClampStrategy(cfg.MaxHistoryMessages, 3, 200, 60);
......
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Tools.MyAgent.Config;
namespace Tools.MyAgent.Agent namespace Tools.MyAgent.Agent
{ {
...@@ -36,7 +36,7 @@ namespace Tools.MyAgent.Agent ...@@ -36,7 +36,7 @@ namespace Tools.MyAgent.Agent
_backup.ApiKey = backupApiKey ?? ""; _backup.ApiKey = backupApiKey ?? "";
_backup.Model = string.IsNullOrEmpty(backupModel) ? "qwen2.5" : backupModel; _backup.Model = string.IsNullOrEmpty(backupModel) ? "qwen2.5" : backupModel;
_backup.Temperature = 0.3; _backup.Temperature = 0.3;
_backup.MaxTokens = 8192; _backup.MaxTokens = AgentConfig.DefaultMaxTokens;
} }
if (!enabled && _failedOver) if (!enabled && _failedOver)
{ {
......
...@@ -9,6 +9,7 @@ using System.Net.Http; ...@@ -9,6 +9,7 @@ using System.Net.Http;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tools.MyAgent.Config;
namespace Tools.MyAgent.Agent namespace Tools.MyAgent.Agent
{ {
...@@ -46,7 +47,7 @@ namespace Tools.MyAgent.Agent ...@@ -46,7 +47,7 @@ namespace Tools.MyAgent.Agent
public string ApiKey { get; set; } = ""; public string ApiKey { get; set; } = "";
public string Model { get; set; } = "deepseek-v4-flash"; public string Model { get; set; } = "deepseek-v4-flash";
public double Temperature { get; set; } = 0.3; public double Temperature { get; set; } = 0.3;
public int MaxTokens { get; set; } = 8192; public int MaxTokens { get; set; } = AgentConfig.DefaultMaxTokens;
/// <summary>获取当前兼容接口公开的模型列表(不影响聊天请求)</summary> /// <summary>获取当前兼容接口公开的模型列表(不影响聊天请求)</summary>
public async Task<(bool Ok, string Message, List<string> Models)> FetchModelsAsync(CancellationToken ct) public async Task<(bool Ok, string Message, List<string> Models)> FetchModelsAsync(CancellationToken ct)
......
...@@ -10,8 +10,8 @@ namespace Tools.MyAgent.Agent ...@@ -10,8 +10,8 @@ namespace Tools.MyAgent.Agent
/// </summary> /// </summary>
public static class ToolSchema public static class ToolSchema
{ {
/// <summary>构建默认工具(核心能力)的 JSON Schema</summary> /// <summary>构建默认工具(包含可选能力)的 JSON Schema</summary>
public static JArray Build() => Build(false); public static JArray Build() => Build(true);
/// <summary> /// <summary>
/// 构建工具 JSON Schema;includeOptional=true 时包含高级/可选工具; /// 构建工具 JSON Schema;includeOptional=true 时包含高级/可选工具;
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
/// </summary> /// </summary>
public sealed class AgentConfig public sealed class AgentConfig
{ {
public const double DefaultTemperature = 0.3;
public const int DefaultMaxTokens = 32768;
public const int DefaultMaxContextTokens = 128000;
// ════════════════ 核心项(主设置页) ════════════════ // ════════════════ 核心项(主设置页) ════════════════
/// <summary>【核心】提供商预设名(DeepSeek / 通义千问 / OpenAI / 本地 Ollama / 自定义)</summary> /// <summary>【核心】提供商预设名(DeepSeek / 通义千问 / OpenAI / 本地 Ollama / 自定义)</summary>
...@@ -52,13 +56,13 @@ ...@@ -52,13 +56,13 @@
// ════════════════ 高级项:生成参数 ════════════════ // ════════════════ 高级项:生成参数 ════════════════
/// <summary>采样温度</summary> /// <summary>采样温度</summary>
public double Temperature { get; set; } = 0.3; public double Temperature { get; set; } = DefaultTemperature;
/// <summary>输出上限(过小会导致长回答被截断残缺;若超出模型上限,客户端会自动减半重试兑底)</summary> /// <summary>输出上限(过小会导致长回答被截断残缺;若超出模型上限,客户端会自动减半重试兑底)</summary>
public int MaxTokens { get; set; } = 8192; public int MaxTokens { get; set; } = DefaultMaxTokens;
/// <summary>上下文 token 预算(超出后自动裁剪历史 / LLM 摘要压缩;0 = 使用模型默认值)</summary> /// <summary>上下文 token 预算(超出后自动裁剪历史 / LLM 摘要压缩;0 = 使用模型默认值)</summary>
public int MaxContextTokens { get; set; } = 32000; public int MaxContextTokens { get; set; } = DefaultMaxContextTokens;
/// <summary>是否使用系统代理(挂 WebRequest.GetSystemWebProxy / HTTPS_PROXY 环境变量)</summary> /// <summary>是否使用系统代理(挂 WebRequest.GetSystemWebProxy / HTTPS_PROXY 环境变量)</summary>
public bool UseSystemProxy { get; set; } = true; public bool UseSystemProxy { get; set; } = true;
...@@ -98,8 +102,8 @@ ...@@ -98,8 +102,8 @@
// ════════════════ 高级项:可选能力 ════════════════ // ════════════════ 高级项:可选能力 ════════════════
/// <summary>是否启用可选/高级工具(db_query、module_patch、img_search、/workflow)</summary> /// <summary>是否启用可选/高级工具(db_query、module_patch、img_search、/workflow);默认启用,可显式关闭</summary>
public bool EnableOptionalTools { get; set; } = false; public bool EnableOptionalTools { get; set; } = true;
/// <summary>是否启用图片提问(多模态,v2.2):启用后粘贴截图随提问以 image_url 发送,需视觉模型支持(如 DeepSeek-VL / qwen-vl);默认启用</summary> /// <summary>是否启用图片提问(多模态,v2.2):启用后粘贴截图随提问以 image_url 发送,需视觉模型支持(如 DeepSeek-VL / qwen-vl);默认启用</summary>
public bool EnableImageInput { get; set; } = true; public bool EnableImageInput { get; set; } = true;
......
...@@ -554,7 +554,7 @@ ...@@ -554,7 +554,7 @@
0}); 0});
this.numMaxTokens.Location = new System.Drawing.Point(384, 28); this.numMaxTokens.Location = new System.Drawing.Point(384, 28);
this.numMaxTokens.Maximum = new decimal(new int[] { this.numMaxTokens.Maximum = new decimal(new int[] {
16384, 65536,
0, 0,
0, 0,
0}); 0});
...@@ -567,7 +567,7 @@ ...@@ -567,7 +567,7 @@
this.numMaxTokens.Size = new System.Drawing.Size(96, 23); this.numMaxTokens.Size = new System.Drawing.Size(96, 23);
this.numMaxTokens.TabIndex = 4; this.numMaxTokens.TabIndex = 4;
this.numMaxTokens.Value = new decimal(new int[] { this.numMaxTokens.Value = new decimal(new int[] {
8192, 32768,
0, 0,
0, 0,
0}); 0});
...@@ -590,7 +590,7 @@ ...@@ -590,7 +590,7 @@
0}); 0});
this.numContext.Location = new System.Drawing.Point(92, 60); this.numContext.Location = new System.Drawing.Point(92, 60);
this.numContext.Maximum = new decimal(new int[] { this.numContext.Maximum = new decimal(new int[] {
200000, 800000,
0, 0,
0, 0,
0}); 0});
...@@ -603,7 +603,7 @@ ...@@ -603,7 +603,7 @@
this.numContext.Size = new System.Drawing.Size(96, 23); this.numContext.Size = new System.Drawing.Size(96, 23);
this.numContext.TabIndex = 6; this.numContext.TabIndex = 6;
this.numContext.Value = new decimal(new int[] { this.numContext.Value = new decimal(new int[] {
32000, 128000,
0, 0,
0, 0,
0}); 0});
......
...@@ -270,9 +270,9 @@ namespace Tools.MyAgent.Forms ...@@ -270,9 +270,9 @@ namespace Tools.MyAgent.Forms
// 基础配置:UI 风格固定为 RichBox(RichTextBox + RTF 渲染),不再提供 WebView 选项 // 基础配置:UI 风格固定为 RichBox(RichTextBox + RTF 渲染),不再提供 WebView 选项
// 高级配置:生成参数 // 高级配置:生成参数
numTemp.Value = ClampDecimalToControl(_config.Temperature, numTemp, 0.3m); numTemp.Value = ClampDecimalToControl(_config.Temperature, numTemp, (decimal)AgentConfig.DefaultTemperature);
numMaxTokens.Value = ClampToControl(_config.MaxTokens, numMaxTokens, 8192); numMaxTokens.Value = ClampToControl(_config.MaxTokens, numMaxTokens, AgentConfig.DefaultMaxTokens);
numContext.Value = ClampToControl(_config.MaxContextTokens, numContext, 32000); numContext.Value = ClampToControl(_config.MaxContextTokens, numContext, AgentConfig.DefaultMaxContextTokens);
chkProxy.Checked = _config.UseSystemProxy; chkProxy.Checked = _config.UseSystemProxy;
// 高级配置:策略参数(R12;越界回退默认,避免 NumericUpDown 赋值抛异常) // 高级配置:策略参数(R12;越界回退默认,避免 NumericUpDown 赋值抛异常)
......
...@@ -27,7 +27,7 @@ namespace Tools.MyAgent ...@@ -27,7 +27,7 @@ namespace Tools.MyAgent
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.panelChat = new System.Windows.Forms.Panel(); this.panelChat = new System.Windows.Forms.Panel();
this.panelBottom = new System.Windows.Forms.Panel(); this.panelBottom = new System.Windows.Forms.Panel();
this.btnSend = new System.Windows.Forms.Button(); this.lblShortcutHint = new System.Windows.Forms.Label();
this.txtInput = new System.Windows.Forms.TextBox(); this.txtInput = new System.Windows.Forms.TextBox();
this.panelToolbar = new System.Windows.Forms.Panel(); this.panelToolbar = new System.Windows.Forms.Panel();
this.lblCopy = new System.Windows.Forms.LinkLabel(); this.lblCopy = new System.Windows.Forms.LinkLabel();
...@@ -54,8 +54,8 @@ namespace Tools.MyAgent ...@@ -54,8 +54,8 @@ namespace Tools.MyAgent
// //
// panelBottom // panelBottom
// //
this.panelBottom.Controls.Add(this.btnSend);
this.panelBottom.Controls.Add(this.txtInput); this.panelBottom.Controls.Add(this.txtInput);
this.panelBottom.Controls.Add(this.lblShortcutHint);
this.panelBottom.Dock = System.Windows.Forms.DockStyle.Bottom; this.panelBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panelBottom.Location = new System.Drawing.Point(0, 490); this.panelBottom.Location = new System.Drawing.Point(0, 490);
this.panelBottom.Margin = new System.Windows.Forms.Padding(4); this.panelBottom.Margin = new System.Windows.Forms.Padding(4);
...@@ -64,20 +64,18 @@ namespace Tools.MyAgent ...@@ -64,20 +64,18 @@ namespace Tools.MyAgent
this.panelBottom.Size = new System.Drawing.Size(817, 148); this.panelBottom.Size = new System.Drawing.Size(817, 148);
this.panelBottom.TabIndex = 1; this.panelBottom.TabIndex = 1;
// //
// btnSend // lblShortcutHint
// //
this.btnSend.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(212))))); this.lblShortcutHint.Dock = System.Windows.Forms.DockStyle.Bottom;
this.btnSend.Dock = System.Windows.Forms.DockStyle.Right; this.lblShortcutHint.Font = new System.Drawing.Font("微软雅黑", 9F);
this.btnSend.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.lblShortcutHint.ForeColor = System.Drawing.Color.Gray;
this.btnSend.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold); this.lblShortcutHint.Location = new System.Drawing.Point(5, 112);
this.btnSend.ForeColor = System.Drawing.Color.White; this.lblShortcutHint.Name = "lblShortcutHint";
this.btnSend.Location = new System.Drawing.Point(723, 6); this.lblShortcutHint.Padding = new System.Windows.Forms.Padding(4, 0, 0, 0);
this.btnSend.Margin = new System.Windows.Forms.Padding(4); this.lblShortcutHint.Size = new System.Drawing.Size(807, 24);
this.btnSend.Name = "btnSend"; this.lblShortcutHint.TabIndex = 2;
this.btnSend.Size = new System.Drawing.Size(89, 136); this.lblShortcutHint.Text = "Enter 发送,Shift + Enter 换行";
this.btnSend.TabIndex = 1; this.lblShortcutHint.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnSend.Text = "发送";
this.btnSend.UseVisualStyleBackColor = false;
// //
// txtInput // txtInput
// //
...@@ -228,7 +226,7 @@ namespace Tools.MyAgent ...@@ -228,7 +226,7 @@ namespace Tools.MyAgent
private System.Windows.Forms.Panel panelChat; private System.Windows.Forms.Panel panelChat;
private System.Windows.Forms.Panel panelBottom; private System.Windows.Forms.Panel panelBottom;
private System.Windows.Forms.Button btnSend; private System.Windows.Forms.Label lblShortcutHint;
private System.Windows.Forms.TextBox txtInput; private System.Windows.Forms.TextBox txtInput;
private System.Windows.Forms.Panel panelToolbar; private System.Windows.Forms.Panel panelToolbar;
private System.Windows.Forms.LinkLabel lblNewChat; private System.Windows.Forms.LinkLabel lblNewChat;
......
...@@ -388,7 +388,7 @@ namespace Tools.MyAgent ...@@ -388,7 +388,7 @@ namespace Tools.MyAgent
cmbScope.SelectedIndexChanged += (s, e) => OnScopeComboChanged(); cmbScope.SelectedIndexChanged += (s, e) => OnScopeComboChanged();
lblSaveKb.LinkClicked += (s, e) => SaveLastAnswerToKb(); lblSaveKb.LinkClicked += (s, e) => SaveLastAnswerToKb();
lblCopy.LinkClicked += (s, e) => CopyLastAnswer(); lblCopy.LinkClicked += (s, e) => CopyLastAnswer();
btnSend.Click += (s, e) => OnSendButtonClick(); // 发送/取消均使用键盘:Enter 发送,ESC 取消
txtInput.KeyDown += OnInputKeyDown; txtInput.KeyDown += OnInputKeyDown;
// 输入框拖入图片文件 → 加入待发送附图列表(与 Ctrl+V 粘贴同一套收图流程) // 输入框拖入图片文件 → 加入待发送附图列表(与 Ctrl+V 粘贴同一套收图流程)
txtInput.AllowDrop = true; txtInput.AllowDrop = true;
...@@ -532,7 +532,7 @@ namespace Tools.MyAgent ...@@ -532,7 +532,7 @@ namespace Tools.MyAgent
// ── 发送 / 取消 ────────────────────────────────── // ── 发送 / 取消 ──────────────────────────────────
private void OnSendButtonClick() private void OnSendOrCancel()
{ {
if (_engine.IsRunning) if (_engine.IsRunning)
{ {
...@@ -568,7 +568,7 @@ namespace Tools.MyAgent ...@@ -568,7 +568,7 @@ namespace Tools.MyAgent
txtInput.Text = ""; txtInput.Text = "";
SetInputEnabled(false); SetInputEnabled(false);
SetButtonState(true); SetShortcutHint(true);
_messages.Add(new ChatMessage _messages.Add(new ChatMessage
{ {
...@@ -770,24 +770,20 @@ namespace Tools.MyAgent ...@@ -770,24 +770,20 @@ namespace Tools.MyAgent
txtInput.Focus(); txtInput.Focus();
} }
private void SetButtonState(bool isRunning) private void SetShortcutHint(bool isRunning)
{ {
if (isRunning) lblShortcutHint.Text = isRunning
{ ? "ESC 取消"
btnSend.Text = "取消"; : "Enter 发送,Shift + Enter 换行";
btnSend.BackColor = Color.FromArgb(220, 50, 50); lblShortcutHint.ForeColor = isRunning
} ? Color.FromArgb(190, 50, 50)
else : Color.Gray;
{
btnSend.Text = "发送";
btnSend.BackColor = Color.FromArgb(0, 120, 212);
}
} }
private void ResetInputState() private void ResetInputState()
{ {
SetInputEnabled(true); SetInputEnabled(true);
SetButtonState(false); SetShortcutHint(false);
txtInput.Focus(); txtInput.Focus();
} }
...@@ -1060,7 +1056,7 @@ namespace Tools.MyAgent ...@@ -1060,7 +1056,7 @@ namespace Tools.MyAgent
// Enter:录入选中命令并作为消息发送 // Enter:录入选中命令并作为消息发送
e.Handled = true; e.SuppressKeyPress = true; e.Handled = true; e.SuppressKeyPress = true;
CommitSelectedCommand(); CommitSelectedCommand();
OnSendButtonClick(); OnSendOrCancel();
return; return;
} }
if (e.KeyCode == Keys.Escape) if (e.KeyCode == Keys.Escape)
...@@ -1098,7 +1094,7 @@ namespace Tools.MyAgent ...@@ -1098,7 +1094,7 @@ namespace Tools.MyAgent
{ {
// Enter:发送(回复中则为取消) // Enter:发送(回复中则为取消)
e.SuppressKeyPress = true; e.SuppressKeyPress = true;
OnSendButtonClick(); OnSendOrCancel();
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment