mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 10:14:51 +00:00
fix(ui): add behavior setting tooltips
Add localized field-level tooltips for Agent and Channel delivery behavior settings.
This commit is contained in:
1 parent
50c8519f01
commit
f077d56ea7
10 files changed
+460
-55
No files matched your search
@@ -1124,16 +1124,26 @@
|
||||
"delivery": {
|
||||
"title": "Delivery Behavior",
|
||||
"description": "Agent-level override for Quick Acknowledgement and Intermediate Replies. Channel settings still win over this.",
|
||||
"modeTip": "Choose whether this agent inherits Workspace behavior or uses its own delivery settings. Channel settings still have the highest priority.",
|
||||
"inherit": "Inherit",
|
||||
"custom": "Custom",
|
||||
"quickAck": "Quick acknowledgement",
|
||||
"quickAckTip": "Sends a short natural receipt before long work starts. It is generated outside the session history and is separate from Show Reasoning.",
|
||||
"intermediate": "Intermediate replies",
|
||||
"intermediateTip": "Sends natural progress bubbles during long or tool-heavy runs. These updates are not added to session history.",
|
||||
"provider": "Provider",
|
||||
"quickAckProviderTip": "Optional provider for quick acknowledgements. Leave empty to use the agent provider; choose a fast, cheap provider here.",
|
||||
"intermediateProviderTip": "Optional provider for intermediate progress. Leave empty to use the agent provider; choose a fast, cheap provider here.",
|
||||
"providerPlaceholder": "Use agent provider",
|
||||
"model": "Model",
|
||||
"quickAckModelTip": "Optional model for quick acknowledgements. Leave empty to use the agent model; custom model names are allowed.",
|
||||
"intermediateModelTip": "Optional model for progress bubbles. Leave empty to use the agent model; custom model names are allowed.",
|
||||
"modelPlaceholder": "Use agent model",
|
||||
"quickAckDelay": "Ack delay (ms)",
|
||||
"timeoutMs": "Timeout (ms)"
|
||||
"quickAckDelayTip": "How long to wait before sending a quick acknowledgement. Increase this if fast answers should avoid an extra bubble.",
|
||||
"timeoutMs": "Timeout (ms)",
|
||||
"quickAckTimeoutTip": "Maximum time to wait for the acknowledgement model before skipping generated acknowledgement.",
|
||||
"intermediateTimeoutTip": "Maximum time to wait for the progress model before skipping an intermediate update."
|
||||
},
|
||||
"toast": {
|
||||
"created": "Agent created",
|
||||
|
||||
@@ -394,6 +394,78 @@
|
||||
"help": "Restrict which tools the agent can use in this group"
|
||||
},
|
||||
"system_prompt": { "label": "System Prompt" },
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"label": "Human-like Delivery",
|
||||
"help": "Channel-level override for delivery behavior. Channel settings win over Agent and Workspace settings."
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"label": "Intermediate Replies",
|
||||
"help": "Send natural progress bubbles during long or tool-heavy runs. These messages are not added to session history."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Intermediate Reply Mode",
|
||||
"help": "Choose whether progress updates are generated by the delivery model or disabled for this channel."
|
||||
},
|
||||
"provider": {
|
||||
"label": "Intermediate Provider",
|
||||
"help": "Optional provider for progress bubbles. Leave empty to inherit the agent provider; pick a fast, cheap provider here."
|
||||
},
|
||||
"model": {
|
||||
"label": "Intermediate Model",
|
||||
"help": "Optional model for progress bubbles. Leave empty to inherit the agent model; custom model names are allowed."
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Intermediate Timeout (ms)",
|
||||
"help": "Maximum time to wait for the delivery model before skipping an intermediate update."
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Intermediate Max Tokens",
|
||||
"help": "Token cap for each generated progress bubble. Keep this small so updates stay short."
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Intermediate Max Chars",
|
||||
"help": "Character cap after generation so progress bubbles do not become full answers."
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"label": "Quick Acknowledgement",
|
||||
"help": "Send a short natural acknowledgement before long work starts. This message is not added to session history."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Quick Ack Mode",
|
||||
"help": "Generated modes use the configured delivery provider/model. Fixed template mode is the only mode that sends template text."
|
||||
},
|
||||
"provider": {
|
||||
"label": "Quick Ack Provider",
|
||||
"help": "Optional provider for quick acknowledgements. Leave empty to inherit the agent provider; pick a fast, cheap provider here."
|
||||
},
|
||||
"model": {
|
||||
"label": "Quick Ack Model",
|
||||
"help": "Optional model for quick acknowledgements. Leave empty to inherit the agent model; custom model names are allowed."
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Quick Ack Timeout (ms)",
|
||||
"help": "Maximum time to wait for the acknowledgement model before skipping generated acknowledgement."
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Quick Ack Max Tokens",
|
||||
"help": "Token cap for the acknowledgement. Keep this small so it reads like a receipt, not an answer."
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Quick Ack Max Chars",
|
||||
"help": "Character cap after generation so acknowledgement bubbles stay compact."
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"label": "Final Reply Splitting",
|
||||
"help": "Split long final answers into multiple channel messages. This is separate from reasoning and progress bubbles."
|
||||
}
|
||||
}
|
||||
},
|
||||
"platform": { "label": "Platform", "help": "Select the platform this Pancake page serves." },
|
||||
"tiktok_type": { "label": "TikTok Type", "help": "Select the TikTok account type for this page" },
|
||||
"features.private_reply": {
|
||||
@@ -432,6 +504,46 @@
|
||||
"always_bubbles": "Always as bubbles",
|
||||
"off": "Off"
|
||||
},
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"true": "Enabled",
|
||||
"false": "Disabled"
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"true": "Enabled",
|
||||
"false": "Disabled"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"sidecar_generated": "Sidecar-generated",
|
||||
"off": "Off"
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"true": "Enabled",
|
||||
"false": "Disabled"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"sidecar_generated": "Sidecar-generated",
|
||||
"llm_generated": "LLM-generated",
|
||||
"fixed_template": "Fixed template",
|
||||
"off": "Off"
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"inherit": "Inherit from gateway",
|
||||
"true": "Enabled",
|
||||
"false": "Disabled"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"lark": "Lark (Global)",
|
||||
"feishu": "Feishu (China)"
|
||||
|
||||
@@ -1109,16 +1109,26 @@
|
||||
"delivery": {
|
||||
"title": "Hành vi gửi tin",
|
||||
"description": "Ghi đè cấp Agent cho Xác nhận nhanh và Phản hồi trung gian. Cấu hình Channel vẫn có ưu tiên cao hơn.",
|
||||
"modeTip": "Chọn agent này kế thừa cấu hình Workspace hay dùng cấu hình gửi tin riêng. Cấu hình Channel vẫn có ưu tiên cao nhất.",
|
||||
"inherit": "Kế thừa",
|
||||
"custom": "Tuỳ chỉnh",
|
||||
"quickAck": "Xác nhận nhanh",
|
||||
"quickAckTip": "Gửi một câu xác nhận ngắn, tự nhiên trước khi tác vụ dài bắt đầu. Tin này được tạo ngoài lịch sử phiên và tách biệt với Hiện suy luận.",
|
||||
"intermediate": "Phản hồi trung gian",
|
||||
"intermediateTip": "Gửi các bubble cập nhật tiến độ tự nhiên trong tác vụ dài hoặc dùng nhiều tool. Các cập nhật này không được thêm vào lịch sử phiên.",
|
||||
"provider": "Provider",
|
||||
"quickAckProviderTip": "Provider tuỳ chọn cho xác nhận nhanh. Để trống để dùng provider của agent; nên chọn provider nhanh và rẻ.",
|
||||
"intermediateProviderTip": "Provider tuỳ chọn cho phản hồi tiến độ. Để trống để dùng provider của agent; nên chọn provider nhanh và rẻ.",
|
||||
"providerPlaceholder": "Dùng provider của agent",
|
||||
"model": "Model",
|
||||
"quickAckModelTip": "Model tuỳ chọn cho xác nhận nhanh. Để trống để dùng model của agent; có thể nhập custom model name.",
|
||||
"intermediateModelTip": "Model tuỳ chọn cho bubble tiến độ. Để trống để dùng model của agent; có thể nhập custom model name.",
|
||||
"modelPlaceholder": "Dùng model của agent",
|
||||
"quickAckDelay": "Độ trễ ack (ms)",
|
||||
"timeoutMs": "Timeout (ms)"
|
||||
"quickAckDelayTip": "Thời gian chờ trước khi gửi xác nhận nhanh. Tăng giá trị này nếu câu trả lời nhanh không cần thêm bubble.",
|
||||
"timeoutMs": "Timeout (ms)",
|
||||
"quickAckTimeoutTip": "Thời gian chờ tối đa cho model xác nhận trước khi bỏ qua xác nhận được generate.",
|
||||
"intermediateTimeoutTip": "Thời gian chờ tối đa cho model tiến độ trước khi bỏ qua cập nhật trung gian."
|
||||
},
|
||||
"toast": {
|
||||
"created": "Đã tạo agent",
|
||||
|
||||
@@ -324,6 +324,78 @@
|
||||
"skills": { "label": "Bộ lọc skill", "help": "Giới hạn skill khả dụng cho nhóm này" },
|
||||
"tools": { "label": "Danh sách công cụ được phép", "help": "Giới hạn công cụ agent có thể dùng trong nhóm này" },
|
||||
"system_prompt": { "label": "Prompt hệ thống" },
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"label": "Hành vi gửi tin tự nhiên",
|
||||
"help": "Ghi đè hành vi gửi tin ở cấp Channel. Cấu hình Channel ưu tiên cao hơn Agent và Workspace."
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"label": "Phản hồi trung gian",
|
||||
"help": "Gửi bubble cập nhật tiến độ tự nhiên trong tác vụ dài hoặc dùng nhiều tool. Tin này không được thêm vào lịch sử phiên."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Chế độ phản hồi trung gian",
|
||||
"help": "Chọn cập nhật tiến độ được generate bằng model gửi tin hay tắt ở channel này."
|
||||
},
|
||||
"provider": {
|
||||
"label": "Intermediate Provider",
|
||||
"help": "Provider tuỳ chọn cho bubble tiến độ. Để trống để kế thừa provider của agent; nên chọn provider nhanh và rẻ."
|
||||
},
|
||||
"model": {
|
||||
"label": "Intermediate Model",
|
||||
"help": "Model tuỳ chọn cho bubble tiến độ. Để trống để kế thừa model của agent; có thể nhập custom model name."
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Intermediate Timeout (ms)",
|
||||
"help": "Thời gian chờ tối đa cho model gửi tin trước khi bỏ qua cập nhật trung gian."
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Intermediate Max Tokens",
|
||||
"help": "Giới hạn token cho mỗi bubble tiến độ. Nên để nhỏ để cập nhật ngắn gọn."
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Intermediate Max Chars",
|
||||
"help": "Giới hạn ký tự sau khi generate để bubble tiến độ không biến thành câu trả lời đầy đủ."
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"label": "Xác nhận nhanh",
|
||||
"help": "Gửi một câu xác nhận ngắn, tự nhiên trước khi tác vụ dài bắt đầu. Tin này không được thêm vào lịch sử phiên."
|
||||
},
|
||||
"mode": {
|
||||
"label": "Chế độ xác nhận nhanh",
|
||||
"help": "Các chế độ generate dùng provider/model gửi tin đã cấu hình. Chỉ chế độ fixed template mới gửi text cố định."
|
||||
},
|
||||
"provider": {
|
||||
"label": "Quick Ack Provider",
|
||||
"help": "Provider tuỳ chọn cho xác nhận nhanh. Để trống để kế thừa provider của agent; nên chọn provider nhanh và rẻ."
|
||||
},
|
||||
"model": {
|
||||
"label": "Quick Ack Model",
|
||||
"help": "Model tuỳ chọn cho xác nhận nhanh. Để trống để kế thừa model của agent; có thể nhập custom model name."
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Quick Ack Timeout (ms)",
|
||||
"help": "Thời gian chờ tối đa cho model xác nhận trước khi bỏ qua xác nhận được generate."
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Quick Ack Max Tokens",
|
||||
"help": "Giới hạn token cho câu xác nhận. Nên để nhỏ để nó giống xác nhận đã nhận việc, không phải câu trả lời."
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Quick Ack Max Chars",
|
||||
"help": "Giới hạn ký tự sau khi generate để bubble xác nhận luôn ngắn gọn."
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"label": "Tách câu trả lời cuối",
|
||||
"help": "Tách câu trả lời dài thành nhiều tin nhắn channel. Tính năng này tách biệt với suy luận và bubble tiến độ."
|
||||
}
|
||||
}
|
||||
},
|
||||
"platform": { "label": "Nền tảng", "help": "Chọn nền tảng mà trang Pancake này phục vụ." },
|
||||
"tiktok_type": { "label": "Loại tài khoản TikTok", "help": "Chọn loại tài khoản TikTok cho trang này" },
|
||||
"features.private_reply": {
|
||||
@@ -362,6 +434,46 @@
|
||||
"always_bubbles": "Luôn thành bubble",
|
||||
"off": "Tắt"
|
||||
},
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"true": "Bật",
|
||||
"false": "Tắt"
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"true": "Bật",
|
||||
"false": "Tắt"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"sidecar_generated": "Sidecar generate",
|
||||
"off": "Tắt"
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"true": "Bật",
|
||||
"false": "Tắt"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"sidecar_generated": "Sidecar generate",
|
||||
"llm_generated": "LLM generate",
|
||||
"fixed_template": "Template cố định",
|
||||
"off": "Tắt"
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"inherit": "Kế thừa từ gateway",
|
||||
"true": "Bật",
|
||||
"false": "Tắt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"lark": "Lark (Quốc tế)",
|
||||
"feishu": "Feishu (Trung Quốc)"
|
||||
|
||||
@@ -1109,16 +1109,26 @@
|
||||
"delivery": {
|
||||
"title": "投递行为",
|
||||
"description": "Agent 级 Quick Acknowledgement 和 Intermediate Replies 覆盖。Channel 设置仍然优先。",
|
||||
"modeTip": "选择此 Agent 继承 Workspace 行为,还是使用自己的投递设置。Channel 设置仍然具有最高优先级。",
|
||||
"inherit": "继承",
|
||||
"custom": "自定义",
|
||||
"quickAck": "快速确认",
|
||||
"quickAckTip": "在长任务开始前发送一条自然的简短确认。此消息不会写入会话历史,并且独立于显示推理。",
|
||||
"intermediate": "中间回复",
|
||||
"intermediateTip": "在长任务或大量工具调用期间发送自然的进度气泡。这些更新不会写入会话历史。",
|
||||
"provider": "Provider",
|
||||
"quickAckProviderTip": "快速确认使用的可选 Provider。留空则使用 Agent Provider;适合选择快速、低成本的 Provider。",
|
||||
"intermediateProviderTip": "中间进度使用的可选 Provider。留空则使用 Agent Provider;适合选择快速、低成本的 Provider。",
|
||||
"providerPlaceholder": "使用 agent provider",
|
||||
"model": "Model",
|
||||
"quickAckModelTip": "快速确认使用的可选模型。留空则使用 Agent 模型;允许输入自定义模型名。",
|
||||
"intermediateModelTip": "进度气泡使用的可选模型。留空则使用 Agent 模型;允许输入自定义模型名。",
|
||||
"modelPlaceholder": "使用 agent model",
|
||||
"quickAckDelay": "确认延迟(毫秒)",
|
||||
"timeoutMs": "超时(毫秒)"
|
||||
"quickAckDelayTip": "发送快速确认前等待的时间。如果快速回答不需要额外气泡,可以调高此值。",
|
||||
"timeoutMs": "超时(毫秒)",
|
||||
"quickAckTimeoutTip": "等待确认模型的最长时间,超时后跳过生成的确认消息。",
|
||||
"intermediateTimeoutTip": "等待进度模型的最长时间,超时后跳过中间更新。"
|
||||
},
|
||||
"toast": {
|
||||
"created": "代理已创建",
|
||||
|
||||
@@ -324,6 +324,78 @@
|
||||
"skills": { "label": "Skill过滤", "help": "限制此群组可用的Skill" },
|
||||
"tools": { "label": "工具白名单", "help": "限制Agent在此群组中可使用的工具" },
|
||||
"system_prompt": { "label": "系统提示词" },
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"label": "自然投递行为",
|
||||
"help": "Channel 级投递行为覆盖。Channel 设置优先于 Agent 和 Workspace 设置。"
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"label": "中间回复",
|
||||
"help": "在长任务或大量工具调用期间发送自然的进度气泡。此消息不会写入会话历史。"
|
||||
},
|
||||
"mode": {
|
||||
"label": "中间回复模式",
|
||||
"help": "选择由投递模型生成进度更新,或在此 Channel 中禁用。"
|
||||
},
|
||||
"provider": {
|
||||
"label": "Intermediate Provider",
|
||||
"help": "进度气泡使用的可选 Provider。留空则继承 Agent Provider;适合选择快速、低成本的 Provider。"
|
||||
},
|
||||
"model": {
|
||||
"label": "Intermediate Model",
|
||||
"help": "进度气泡使用的可选模型。留空则继承 Agent 模型;允许输入自定义模型名。"
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Intermediate Timeout (ms)",
|
||||
"help": "等待投递模型的最长时间,超时后跳过中间更新。"
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Intermediate Max Tokens",
|
||||
"help": "每条进度气泡的 token 上限。保持较小可让更新更简短。"
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Intermediate Max Chars",
|
||||
"help": "生成后的字符上限,防止进度气泡变成完整回答。"
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"label": "快速确认",
|
||||
"help": "在长任务开始前发送一条自然的简短确认。此消息不会写入会话历史。"
|
||||
},
|
||||
"mode": {
|
||||
"label": "快速确认模式",
|
||||
"help": "生成模式使用配置的投递 Provider/模型。只有固定模板模式会发送模板文本。"
|
||||
},
|
||||
"provider": {
|
||||
"label": "Quick Ack Provider",
|
||||
"help": "快速确认使用的可选 Provider。留空则继承 Agent Provider;适合选择快速、低成本的 Provider。"
|
||||
},
|
||||
"model": {
|
||||
"label": "Quick Ack Model",
|
||||
"help": "快速确认使用的可选模型。留空则继承 Agent 模型;允许输入自定义模型名。"
|
||||
},
|
||||
"timeout_ms": {
|
||||
"label": "Quick Ack Timeout (ms)",
|
||||
"help": "等待确认模型的最长时间,超时后跳过生成的确认消息。"
|
||||
},
|
||||
"max_tokens": {
|
||||
"label": "Quick Ack Max Tokens",
|
||||
"help": "确认消息的 token 上限。保持较小可让它像确认收到,而不是完整回答。"
|
||||
},
|
||||
"max_chars": {
|
||||
"label": "Quick Ack Max Chars",
|
||||
"help": "生成后的字符上限,确保确认气泡保持简短。"
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"label": "最终回复拆分",
|
||||
"help": "将较长的最终回答拆分为多条 Channel 消息。此功能独立于推理和进度气泡。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"platform": { "label": "平台", "help": "选择此 Pancake 页面所服务的平台。" },
|
||||
"tiktok_type": { "label": "TikTok 类型", "help": "选择此页面的 TikTok 账户类型" },
|
||||
"features.private_reply": {
|
||||
@@ -362,6 +434,46 @@
|
||||
"always_bubbles": "始终作为气泡",
|
||||
"off": "关闭"
|
||||
},
|
||||
"chat_behavior": {
|
||||
"enabled": {
|
||||
"inherit": "继承自 gateway",
|
||||
"true": "启用",
|
||||
"false": "禁用"
|
||||
},
|
||||
"intermediate_replies": {
|
||||
"enabled": {
|
||||
"inherit": "继承自 gateway",
|
||||
"true": "启用",
|
||||
"false": "禁用"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "继承自 gateway",
|
||||
"sidecar_generated": "Sidecar 生成",
|
||||
"off": "关闭"
|
||||
}
|
||||
},
|
||||
"quick_ack": {
|
||||
"enabled": {
|
||||
"inherit": "继承自 gateway",
|
||||
"true": "启用",
|
||||
"false": "禁用"
|
||||
},
|
||||
"mode": {
|
||||
"inherit": "继承自 gateway",
|
||||
"sidecar_generated": "Sidecar 生成",
|
||||
"llm_generated": "LLM 生成",
|
||||
"fixed_template": "固定模板",
|
||||
"off": "关闭"
|
||||
}
|
||||
},
|
||||
"final_split": {
|
||||
"enabled": {
|
||||
"inherit": "继承自 gateway",
|
||||
"true": "启用",
|
||||
"false": "禁用"
|
||||
}
|
||||
}
|
||||
},
|
||||
"domain": {
|
||||
"lark": "Lark(国际版)",
|
||||
"feishu": "飞书(中国版)"
|
||||
|
||||
@@ -3,9 +3,9 @@ import { useTranslation } from "react-i18next";
|
||||
import { Save, Settings, Loader2 } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { InfoLabel } from "@/components/shared/info-label";
|
||||
import { ProviderModelSelect } from "@/components/shared/provider-model-select";
|
||||
import {
|
||||
Dialog, DialogContent, DialogHeader, DialogTitle,
|
||||
@@ -312,7 +312,9 @@ function DeliveryBehaviorSection({
|
||||
<div className="space-y-3 rounded-md border p-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium">{t("delivery.title")}</h3>
|
||||
<InfoLabel tip={t("delivery.modeTip")} labelClassName="text-sm font-medium">
|
||||
{t("delivery.title")}
|
||||
</InfoLabel>
|
||||
<p className="text-xs text-muted-foreground">{t("delivery.description")}</p>
|
||||
</div>
|
||||
<Select value={mode} onValueChange={(next) => onModeChange(next as "inherit" | "custom")}>
|
||||
@@ -328,39 +330,59 @@ function DeliveryBehaviorSection({
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<Label>{t("delivery.quickAck")}</Label>
|
||||
<InfoLabel tip={t("delivery.quickAckTip")}>{t("delivery.quickAck")}</InfoLabel>
|
||||
<Switch checked={value.quick_ack?.enabled ?? true} disabled={disabled} onCheckedChange={(enabled) => patchQuick({ enabled })} />
|
||||
</div>
|
||||
<DeliveryProviderFields
|
||||
disabled={disabled}
|
||||
provider={value.quick_ack?.provider ?? ""}
|
||||
model={value.quick_ack?.model ?? ""}
|
||||
providerTip={t("delivery.quickAckProviderTip")}
|
||||
modelTip={t("delivery.quickAckModelTip")}
|
||||
onProvider={(provider) => patchQuick({ provider, model: "" })}
|
||||
onModel={(model) => patchQuick({ model })}
|
||||
/>
|
||||
<NumberField label={t("delivery.quickAckDelay")} value={value.quick_ack?.min_delay_ms ?? 1000} disabled={disabled} onChange={(min_delay_ms) => patchQuick({ min_delay_ms })} />
|
||||
<NumberField label={t("delivery.timeoutMs")} value={value.quick_ack?.timeout_ms ?? 2500} disabled={disabled} onChange={(timeout_ms) => patchQuick({ timeout_ms })} />
|
||||
<NumberField label={t("delivery.quickAckDelay")} tip={t("delivery.quickAckDelayTip")} value={value.quick_ack?.min_delay_ms ?? 1000} disabled={disabled} onChange={(min_delay_ms) => patchQuick({ min_delay_ms })} />
|
||||
<NumberField label={t("delivery.timeoutMs")} tip={t("delivery.quickAckTimeoutTip")} value={value.quick_ack?.timeout_ms ?? 2500} disabled={disabled} onChange={(timeout_ms) => patchQuick({ timeout_ms })} />
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<Label>{t("delivery.intermediate")}</Label>
|
||||
<InfoLabel tip={t("delivery.intermediateTip")}>{t("delivery.intermediate")}</InfoLabel>
|
||||
<Switch checked={value.intermediate_replies?.enabled ?? false} disabled={disabled} onCheckedChange={(enabled) => patchIntermediate({ enabled })} />
|
||||
</div>
|
||||
<DeliveryProviderFields
|
||||
disabled={disabled}
|
||||
provider={value.intermediate_replies?.provider ?? ""}
|
||||
model={value.intermediate_replies?.model ?? ""}
|
||||
providerTip={t("delivery.intermediateProviderTip")}
|
||||
modelTip={t("delivery.intermediateModelTip")}
|
||||
onProvider={(provider) => patchIntermediate({ provider, model: "" })}
|
||||
onModel={(model) => patchIntermediate({ model })}
|
||||
/>
|
||||
<NumberField label={t("delivery.timeoutMs")} value={value.intermediate_replies?.timeout_ms ?? 2500} disabled={disabled} onChange={(timeout_ms) => patchIntermediate({ timeout_ms })} />
|
||||
<NumberField label={t("delivery.timeoutMs")} tip={t("delivery.intermediateTimeoutTip")} value={value.intermediate_replies?.timeout_ms ?? 2500} disabled={disabled} onChange={(timeout_ms) => patchIntermediate({ timeout_ms })} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DeliveryProviderFields({ disabled, provider, model, onProvider, onModel }: { disabled: boolean; provider: string; model: string; onProvider: (value: string) => void; onModel: (value: string) => void }) {
|
||||
function DeliveryProviderFields({
|
||||
disabled,
|
||||
provider,
|
||||
model,
|
||||
providerTip,
|
||||
modelTip,
|
||||
onProvider,
|
||||
onModel,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
provider: string;
|
||||
model: string;
|
||||
providerTip: string;
|
||||
modelTip: string;
|
||||
onProvider: (value: string) => void;
|
||||
onModel: (value: string) => void;
|
||||
}) {
|
||||
const { t } = useTranslation("agents");
|
||||
return (
|
||||
<ProviderModelSelect
|
||||
@@ -372,16 +394,18 @@ function DeliveryProviderFields({ disabled, provider, model, onProvider, onModel
|
||||
allowEmpty
|
||||
providerLabel={t("delivery.provider")}
|
||||
modelLabel={t("delivery.model")}
|
||||
providerTip={providerTip}
|
||||
modelTip={modelTip}
|
||||
providerPlaceholder={t("delivery.providerPlaceholder")}
|
||||
modelPlaceholder={t("delivery.modelPlaceholder")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function NumberField({ label, value, disabled, onChange }: { label: string; value: number; disabled: boolean; onChange: (value: number) => void }) {
|
||||
function NumberField({ label, tip, value, disabled, onChange }: { label: string; tip: string; value: number; disabled: boolean; onChange: (value: number) => void }) {
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>{label}</Label>
|
||||
<InfoLabel tip={tip}>{label}</InfoLabel>
|
||||
<Input className="text-base md:text-sm" type="number" min={0} value={value} disabled={disabled} onChange={(e) => onChange(Number(e.target.value))} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { ToolNameSelect } from "@/components/shared/tool-name-select";
|
||||
import { SkillNameSelect } from "@/components/shared/skill-name-select";
|
||||
import { ProviderModelSelect } from "@/components/shared/provider-model-select";
|
||||
import { InfoLabel } from "@/components/shared/info-label";
|
||||
import { BitrixPortalSelect } from "./bitrix24/bitrix-portal-select";
|
||||
import { deliveryModelKey, isDeliveryModelKey, isDeliveryProviderKey } from "./channel-delivery-provider-fields";
|
||||
import type { FieldDef } from "./channel-schemas";
|
||||
@@ -102,6 +103,14 @@ export function ChannelFields({ fields, values, onChange, idPrefix, isEdit, cont
|
||||
);
|
||||
}
|
||||
|
||||
function isChatBehaviorField(key: string) {
|
||||
return key.startsWith("chat_behavior.");
|
||||
}
|
||||
|
||||
function FieldLabel({ htmlFor, text, tip }: { htmlFor?: string; text: string; tip?: string }) {
|
||||
return tip ? <InfoLabel tip={tip}>{text}</InfoLabel> : <Label htmlFor={htmlFor}>{text}</Label>;
|
||||
}
|
||||
|
||||
function DeliveryProviderModelField({
|
||||
providerField,
|
||||
modelField,
|
||||
@@ -170,6 +179,8 @@ function FieldRenderer({
|
||||
// i18n: try "fieldConfig.<key>.label" / "fieldConfig.<key>.help", fall back to hardcoded schema string
|
||||
const label = t(`fieldConfig.${field.key}.label`, { defaultValue: field.label });
|
||||
const help = field.help ? t(`fieldConfig.${field.key}.help`, { defaultValue: field.help }) : "";
|
||||
const tooltipHelp = isChatBehaviorField(field.key) && help ? help : undefined;
|
||||
const inlineHelp = tooltipHelp ? "" : help;
|
||||
const resolvedHint = disabledHint ? t(disabledHint, { defaultValue: disabledHint }) : undefined;
|
||||
const labelSuffix = field.required && !isEdit ? " *" : "";
|
||||
const editHint = isEdit && field.type === "password" ? ` ${t("form.credentialsHint")}` : "";
|
||||
@@ -184,24 +195,20 @@ function FieldRenderer({
|
||||
if (channelType === "bitrix24" && field.key === "portal" && field.type === "text") {
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={id}>
|
||||
{label}{labelSuffix}
|
||||
</Label>
|
||||
<FieldLabel htmlFor={id} text={`${label}${labelSuffix}`} tip={tooltipHelp} />
|
||||
<BitrixPortalSelect
|
||||
value={(value as string) ?? ""}
|
||||
onChange={onChange}
|
||||
onCreateRequest={onPortalCreateRequest ?? (() => {})}
|
||||
onResumeAuthorize={onPortalResumeAuthorize}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={id}>
|
||||
{label}{labelSuffix}{editHint}
|
||||
</Label>
|
||||
<FieldLabel htmlFor={id} text={`${label}${labelSuffix}${editHint}`} tip={tooltipHelp} />
|
||||
<Input
|
||||
id={id}
|
||||
type={field.type}
|
||||
@@ -209,14 +216,14 @@ function FieldRenderer({
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case "number":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={id}>{label}{labelSuffix}</Label>
|
||||
<FieldLabel htmlFor={id} text={`${label}${labelSuffix}`} tip={tooltipHelp} />
|
||||
<Input
|
||||
id={id}
|
||||
type="number"
|
||||
@@ -224,12 +231,12 @@ function FieldRenderer({
|
||||
onChange={(e) => onChange(e.target.value ? Number(e.target.value) : undefined)}
|
||||
placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : undefined}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case "boolean": {
|
||||
const boolHint = resolvedHint || help;
|
||||
const boolHint = resolvedHint || inlineHelp;
|
||||
return (
|
||||
<div className={`grid gap-1${disabled ? " opacity-50" : ""}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -239,7 +246,7 @@ function FieldRenderer({
|
||||
onCheckedChange={(v) => onChange(v)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
<FieldLabel htmlFor={id} text={label} tip={tooltipHelp} />
|
||||
</div>
|
||||
{boolHint && <p className="text-xs text-muted-foreground ml-9">{boolHint}</p>}
|
||||
</div>
|
||||
@@ -249,7 +256,7 @@ function FieldRenderer({
|
||||
case "select":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>{label}{labelSuffix}</Label>
|
||||
<FieldLabel text={`${label}${labelSuffix}`} tip={tooltipHelp} />
|
||||
<Select
|
||||
value={(value as string) ?? (field.defaultValue as string) ?? ""}
|
||||
onValueChange={(v) => onChange(v)}
|
||||
@@ -265,7 +272,7 @@ function FieldRenderer({
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -281,7 +288,7 @@ function FieldRenderer({
|
||||
const selectValue = (value as string) || INHERIT;
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>{label}</Label>
|
||||
<FieldLabel text={label} tip={tooltipHelp} />
|
||||
<Select
|
||||
value={selectValue}
|
||||
onValueChange={(v) => onChange(v === INHERIT ? undefined : v)}
|
||||
@@ -297,7 +304,7 @@ function FieldRenderer({
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -321,7 +328,7 @@ function FieldRenderer({
|
||||
|
||||
return (
|
||||
<div className={`grid gap-1.5${disabled ? " opacity-50" : ""}`}>
|
||||
<Label>{label}</Label>
|
||||
<FieldLabel text={label} tip={tooltipHelp} />
|
||||
<Select value={boolToStr(value)} onValueChange={(v) => onChange(strToBool(v))} disabled={disabled}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
@@ -333,7 +340,7 @@ function FieldRenderer({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{resolvedHint && <p className="text-xs text-muted-foreground">{resolvedHint}</p>}
|
||||
{!resolvedHint && help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{!resolvedHint && inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -341,7 +348,7 @@ function FieldRenderer({
|
||||
case "textarea":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
<FieldLabel htmlFor={id} text={label} tip={tooltipHelp} />
|
||||
<Textarea
|
||||
id={id}
|
||||
value={(value as string) ?? ""}
|
||||
@@ -349,46 +356,46 @@ function FieldRenderer({
|
||||
placeholder={field.placeholder}
|
||||
rows={3}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case "tool-select":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>{label}</Label>
|
||||
<FieldLabel text={label} tip={tooltipHelp} />
|
||||
<ToolNameSelect
|
||||
value={(value as string[]) ?? []}
|
||||
onChange={(v) => onChange(v.length > 0 ? v : undefined)}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case "skill-select":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label>{label}</Label>
|
||||
<FieldLabel text={label} tip={tooltipHelp} />
|
||||
<SkillNameSelect
|
||||
value={(value as string[]) ?? []}
|
||||
onChange={(v) => onChange(v.length > 0 ? v : undefined)}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case "tags":
|
||||
return (
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
<FieldLabel htmlFor={id} text={label} tip={tooltipHelp} />
|
||||
<MultiUserPicker
|
||||
value={(value as string[]) ?? []}
|
||||
onChange={(v) => onChange(v.length > 0 ? v : undefined)}
|
||||
placeholder={field.placeholder ?? t("groupOverrides.fields.allowedUsersPlaceholder")}
|
||||
/>
|
||||
{help && <p className="text-xs text-muted-foreground">{help}</p>}
|
||||
{inlineHelp && <p className="text-xs text-muted-foreground">{inlineHelp}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -45,6 +45,14 @@ describe("telegram configSchema", () => {
|
||||
expect(isDeliveryModelKey("chat_behavior.intermediate_replies.model")).toBe(true);
|
||||
expect(deliveryModelKey("chat_behavior.intermediate_replies.provider")).toBe("chat_behavior.intermediate_replies.model");
|
||||
});
|
||||
|
||||
it("documents every channel behavior field for tooltip rendering", () => {
|
||||
const behaviorFields = telegramConfig.filter((field) => field.key.startsWith("chat_behavior."));
|
||||
expect(behaviorFields.length).toBeGreaterThan(0);
|
||||
for (const field of behaviorFields) {
|
||||
expect(field.help?.trim(), `${field.key} should have tooltip help`).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("pancake configSchema", () => {
|
||||
|
||||
@@ -36,22 +36,22 @@ const quickAckModeOptions = [
|
||||
];
|
||||
|
||||
const chatBehaviorOverrideFields: FieldDef[] = [
|
||||
{ key: "chat_behavior.enabled", label: "Human-like Delivery", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Override gateway acknowledgement, intermediate progress, and final reply splitting." },
|
||||
{ key: "chat_behavior.intermediate_replies.enabled", label: "Intermediate Replies", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Send natural sidecar progress updates during tool phases without adding them to session history." },
|
||||
{ key: "chat_behavior.intermediate_replies.mode", label: "Intermediate Reply Mode", type: "select", options: [{ value: "inherit", label: "Inherit from gateway" }, { value: "sidecar_generated", label: "Sidecar-generated" }, { value: "off", label: "Off" }], defaultValue: "inherit" },
|
||||
{ key: "chat_behavior.intermediate_replies.provider", label: "Intermediate Provider", type: "text", placeholder: "Use agent provider", help: "Optional cheap provider for sidecar progress updates." },
|
||||
{ key: "chat_behavior.intermediate_replies.model", label: "Intermediate Model", type: "text", placeholder: "Use agent model" },
|
||||
{ key: "chat_behavior.intermediate_replies.timeout_ms", label: "Intermediate Timeout (ms)", type: "number", defaultValue: 2500 },
|
||||
{ key: "chat_behavior.intermediate_replies.max_tokens", label: "Intermediate Max Tokens", type: "number", defaultValue: 60 },
|
||||
{ key: "chat_behavior.intermediate_replies.max_chars", label: "Intermediate Max Chars", type: "number", defaultValue: 180 },
|
||||
{ key: "chat_behavior.quick_ack.enabled", label: "Quick Acknowledgement", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Override quick acknowledgement for this channel." },
|
||||
{ key: "chat_behavior.quick_ack.mode", label: "Quick Ack Mode", type: "select", options: quickAckModeOptions, defaultValue: "inherit", help: "Generated acknowledgement uses the configured sidecar provider/model. Fixed template mode is the only mode that sends template text." },
|
||||
{ key: "chat_behavior.quick_ack.provider", label: "Quick Ack Provider", type: "text", placeholder: "Use agent provider", help: "Optional cheap provider for quick acknowledgements." },
|
||||
{ key: "chat_behavior.quick_ack.model", label: "Quick Ack Model", type: "text", placeholder: "Use agent model" },
|
||||
{ key: "chat_behavior.quick_ack.timeout_ms", label: "Quick Ack Timeout (ms)", type: "number", defaultValue: 2500 },
|
||||
{ key: "chat_behavior.quick_ack.max_tokens", label: "Quick Ack Max Tokens", type: "number", defaultValue: 40 },
|
||||
{ key: "chat_behavior.quick_ack.max_chars", label: "Quick Ack Max Chars", type: "number", defaultValue: 120 },
|
||||
{ key: "chat_behavior.final_split.enabled", label: "Final Reply Splitting", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Override final multi-message splitting for this channel." },
|
||||
{ key: "chat_behavior.enabled", label: "Human-like Delivery", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Channel-level override for delivery behavior. Channel settings win over Agent and Workspace settings." },
|
||||
{ key: "chat_behavior.intermediate_replies.enabled", label: "Intermediate Replies", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Send natural progress bubbles during long or tool-heavy runs. These messages are not added to session history." },
|
||||
{ key: "chat_behavior.intermediate_replies.mode", label: "Intermediate Reply Mode", type: "select", options: [{ value: "inherit", label: "Inherit from gateway" }, { value: "sidecar_generated", label: "Sidecar-generated" }, { value: "off", label: "Off" }], defaultValue: "inherit", help: "Choose whether progress updates are generated by the delivery model or disabled for this channel." },
|
||||
{ key: "chat_behavior.intermediate_replies.provider", label: "Intermediate Provider", type: "text", placeholder: "Use agent provider", help: "Optional provider for progress bubbles. Leave empty to inherit the agent provider; pick a fast, cheap provider here." },
|
||||
{ key: "chat_behavior.intermediate_replies.model", label: "Intermediate Model", type: "text", placeholder: "Use agent model", help: "Optional model for progress bubbles. Leave empty to inherit the agent model; custom model names are allowed." },
|
||||
{ key: "chat_behavior.intermediate_replies.timeout_ms", label: "Intermediate Timeout (ms)", type: "number", defaultValue: 2500, help: "Maximum time to wait for the delivery model before skipping an intermediate update." },
|
||||
{ key: "chat_behavior.intermediate_replies.max_tokens", label: "Intermediate Max Tokens", type: "number", defaultValue: 60, help: "Token cap for each generated progress bubble. Keep this small so updates stay short." },
|
||||
{ key: "chat_behavior.intermediate_replies.max_chars", label: "Intermediate Max Chars", type: "number", defaultValue: 180, help: "Character cap after generation so progress bubbles do not become full answers." },
|
||||
{ key: "chat_behavior.quick_ack.enabled", label: "Quick Acknowledgement", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Send a short natural acknowledgement before long work starts. This message is not added to session history." },
|
||||
{ key: "chat_behavior.quick_ack.mode", label: "Quick Ack Mode", type: "select", options: quickAckModeOptions, defaultValue: "inherit", help: "Generated modes use the configured delivery provider/model. Fixed template mode is the only mode that sends template text." },
|
||||
{ key: "chat_behavior.quick_ack.provider", label: "Quick Ack Provider", type: "text", placeholder: "Use agent provider", help: "Optional provider for quick acknowledgements. Leave empty to inherit the agent provider; pick a fast, cheap provider here." },
|
||||
{ key: "chat_behavior.quick_ack.model", label: "Quick Ack Model", type: "text", placeholder: "Use agent model", help: "Optional model for quick acknowledgements. Leave empty to inherit the agent model; custom model names are allowed." },
|
||||
{ key: "chat_behavior.quick_ack.timeout_ms", label: "Quick Ack Timeout (ms)", type: "number", defaultValue: 2500, help: "Maximum time to wait for the acknowledgement model before skipping generated acknowledgement." },
|
||||
{ key: "chat_behavior.quick_ack.max_tokens", label: "Quick Ack Max Tokens", type: "number", defaultValue: 40, help: "Token cap for the acknowledgement. Keep this small so it reads like a receipt, not an answer." },
|
||||
{ key: "chat_behavior.quick_ack.max_chars", label: "Quick Ack Max Chars", type: "number", defaultValue: 120, help: "Character cap after generation so acknowledgement bubbles stay compact." },
|
||||
{ key: "chat_behavior.final_split.enabled", label: "Final Reply Splitting", type: "select", options: inheritToggleOptions, defaultValue: "inherit", help: "Split long final answers into multiple channel messages. This is separate from reasoning and progress bubbles." },
|
||||
];
|
||||
|
||||
const dmPolicyOptions = [
|
||||
|
||||
Reference in new issue
Block a user