feat: Agent-Einstellung 'Rückfragen erlauben' (allowUserChoice)
- Neues Feld AllowUserChoice (bool, default true) im AgentRecord - DB-Migration: allow_user_choice Spalte mit DEFAULT 1 - Agent-Form: Checkbox 'Rückfragen erlauben' nach 'Tool-Nutzung erzwingen' - ToolService.GetToolDefinitions: neuer Parameter includeUserChoice - ask_user_choice Tool wird nur eingebunden wenn Agent es erlaubt - Review-Agents und Non-Streaming (Cronjobs) erhalten nie ask_user_choice - ChatEndpoint reicht Agent.AllowUserChoice an StreamChat durch
This commit is contained in:
1 parent
5f3e308975
commit
89ceb61948
10 files changed
+26
-36
No files matched your search
@@ -65,6 +65,7 @@ public static class AgentEndpoint
|
||||
UseMemory = !body.TryGetProperty("useMemory", out var um) || um.GetBoolean(),
|
||||
UseWebSearch = body.TryGetProperty("webSearchVersion", out var wsv) && !string.IsNullOrEmpty(wsv.GetString()),
|
||||
WebSearchVersion = body.TryGetProperty("webSearchVersion", out var wsv2) ? wsv2.GetString() ?? "" : "",
|
||||
AllowUserChoice = !body.TryGetProperty("allowUserChoice", out var auc) || auc.GetBoolean(),
|
||||
AvatarScale = body.TryGetProperty("avatarScale", out var asc) ? asc.GetDouble() : 1.0,
|
||||
AvatarOffsetX = body.TryGetProperty("avatarOffsetX", out var aox) ? aox.GetDouble() : 0,
|
||||
AvatarOffsetY = body.TryGetProperty("avatarOffsetY", out var aoy) ? aoy.GetDouble() : 0
|
||||
@@ -103,6 +104,7 @@ public static class AgentEndpoint
|
||||
agent.WebSearchVersion = wsv.GetString() ?? "";
|
||||
agent.UseWebSearch = !string.IsNullOrEmpty(agent.WebSearchVersion);
|
||||
}
|
||||
if (body.TryGetProperty("allowUserChoice", out var auc)) agent.AllowUserChoice = auc.GetBoolean();
|
||||
if (body.TryGetProperty("avatarScale", out var asc)) agent.AvatarScale = asc.GetDouble();
|
||||
if (body.TryGetProperty("avatarOffsetX", out var aox)) agent.AvatarOffsetX = aox.GetDouble();
|
||||
if (body.TryGetProperty("avatarOffsetY", out var aoy)) agent.AvatarOffsetY = aoy.GetDouble();
|
||||
|
||||
@@ -132,7 +132,7 @@ public static class ChatEndpoint
|
||||
|
||||
try
|
||||
{
|
||||
await anthropic.StreamChat(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, ctx.Workspace, sessionId, agentId: ctx.AgentId, useMemory: ctx.UseMemory, webSearchVersion: ctx.WebSearchVersion, maxIterations: ctx.MaxIterations, toolChoice: effectiveToolChoice, review: ctx.Review, finalizer: ctx.Finalizer, cancellationToken: linkedCts.Token);
|
||||
await anthropic.StreamChat(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, ctx.Workspace, sessionId, agentId: ctx.AgentId, useMemory: ctx.UseMemory, webSearchVersion: ctx.WebSearchVersion, maxIterations: ctx.MaxIterations, toolChoice: effectiveToolChoice, review: ctx.Review, finalizer: ctx.Finalizer, allowUserChoice: ctx.Agent?.AllowUserChoice ?? true, cancellationToken: linkedCts.Token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ public class AgentRecord
|
||||
public bool UseMemory { get; set; } = true;
|
||||
public bool UseWebSearch { get; set; }
|
||||
public string WebSearchVersion { get; set; } = "";
|
||||
public bool AllowUserChoice { get; set; } = true;
|
||||
public double AvatarScale { get; set; } = 1.0;
|
||||
public double AvatarOffsetX { get; set; }
|
||||
public double AvatarOffsetY { get; set; }
|
||||
|
||||
@@ -49,6 +49,7 @@ public class AnthropicService
|
||||
string toolChoice = "any",
|
||||
ReviewContext review = null,
|
||||
FinalizerContext finalizer = null,
|
||||
bool allowUserChoice = true,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
@@ -92,7 +93,7 @@ public class AnthropicService
|
||||
{
|
||||
var tools = new List<object>();
|
||||
if (hasTools)
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory));
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory, includeUserChoice: allowUserChoice));
|
||||
if (hasWebSearch)
|
||||
tools.Add(new { type = webSearchVersion, name = "web_search", max_uses = 5 });
|
||||
payload["tools"] = tools;
|
||||
@@ -543,7 +544,7 @@ public class AnthropicService
|
||||
{
|
||||
var tools = new List<object>();
|
||||
if (hasTools)
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory));
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory, includeUserChoice: false));
|
||||
if (hasWebSearch)
|
||||
tools.Add(new { type = webSearchVersion, name = "web_search", max_uses = 5 });
|
||||
payload["tools"] = tools;
|
||||
@@ -768,7 +769,7 @@ public class AnthropicService
|
||||
{
|
||||
var tools = new List<object>();
|
||||
if (hasTools)
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory));
|
||||
tools.AddRange(_toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory, includeUserChoice: false));
|
||||
if (hasWebSearch)
|
||||
tools.Add(new { type = ctx.WebSearchVersion, name = "web_search", max_uses = 5 });
|
||||
payload["tools"] = tools;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class ChatService
|
||||
var includeMemory = agent.UseMemory && !string.IsNullOrEmpty(agent.AgentId);
|
||||
|
||||
var toolDefs = (hasWorkspace || includeMemory)
|
||||
? _toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory)
|
||||
? _toolService.GetToolDefinitions(includeFileTools: hasWorkspace, includeMemory: includeMemory, includeUserChoice: agent.AllowUserChoice)
|
||||
: Array.Empty<object>();
|
||||
var toolNames = toolDefs.Length > 0
|
||||
? JsonSerializer.Serialize(toolDefs.Select(td =>
|
||||
|
||||
@@ -178,6 +178,7 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "agents", "avatar_offset_x", "REAL NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "agents", "avatar_offset_y", "REAL NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "sessions", "finalizer_agent_id", "TEXT");
|
||||
TryAddColumn(conn, "agents", "allow_user_choice", "INTEGER NOT NULL DEFAULT 1");
|
||||
|
||||
conn.Execute(@"
|
||||
CREATE TABLE IF NOT EXISTS agent_skills (
|
||||
@@ -330,8 +331,8 @@ public class DatabaseService
|
||||
agent.CreatedAt = now;
|
||||
agent.UpdatedAt = now;
|
||||
await conn.ExecuteAsync(@"
|
||||
INSERT INTO agents (agent_id, user_id, name, avatar, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_web_search, web_search_version, avatar_scale, avatar_offset_x, avatar_offset_y, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @UserId, @Name, @Avatar, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseWebSearch, @WebSearchVersion, @AvatarScale, @AvatarOffsetX, @AvatarOffsetY, 0, @CreatedAt, @UpdatedAt)
|
||||
INSERT INTO agents (agent_id, user_id, name, avatar, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_web_search, web_search_version, allow_user_choice, avatar_scale, avatar_offset_x, avatar_offset_y, is_deleted, created_at, updated_at)
|
||||
VALUES (@AgentId, @UserId, @Name, @Avatar, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseWebSearch, @WebSearchVersion, @AllowUserChoice, @AvatarScale, @AvatarOffsetX, @AvatarOffsetY, 0, @CreatedAt, @UpdatedAt)
|
||||
", agent);
|
||||
return agent;
|
||||
}
|
||||
@@ -359,6 +360,7 @@ public class DatabaseService
|
||||
model = @Model, tool_choice = @ToolChoice,
|
||||
custom_commands = @CustomCommands, auto_commit = @AutoCommit,
|
||||
use_soul = @UseSoul, use_identity = @UseIdentity, use_user_info = @UseUserInfo, use_memory = @UseMemory, use_web_search = @UseWebSearch, web_search_version = @WebSearchVersion,
|
||||
allow_user_choice = @AllowUserChoice,
|
||||
avatar_scale = @AvatarScale, avatar_offset_x = @AvatarOffsetX, avatar_offset_y = @AvatarOffsetY, updated_at = @UpdatedAt
|
||||
WHERE agent_id = @AgentId AND user_id = @UserId
|
||||
", agent);
|
||||
|
||||
@@ -17,11 +17,11 @@ public class ToolService
|
||||
{
|
||||
public const string AskUserChoiceToolName = "ask_user_choice";
|
||||
|
||||
public object[] GetToolDefinitions(bool includeFileTools = false, bool includeMemory = false)
|
||||
public object[] GetToolDefinitions(bool includeFileTools = false, bool includeMemory = false, bool includeUserChoice = true)
|
||||
{
|
||||
var allTools = new List<object>();
|
||||
// ask_user_choice ist immer verfügbar wenn Tools aktiv sind
|
||||
allTools.Add(GetAskUserChoiceTool());
|
||||
if (includeUserChoice)
|
||||
allTools.Add(GetAskUserChoiceTool());
|
||||
if (includeFileTools)
|
||||
allTools.AddRange(GetFileTools());
|
||||
if (includeMemory)
|
||||
|
||||
+3
-26
@@ -1145,15 +1145,6 @@
|
||||
max-width: 80%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--box-spacing);
|
||||
}
|
||||
|
||||
.choice-question {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.choice-question p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.choice-buttons {
|
||||
@@ -1163,24 +1154,15 @@
|
||||
}
|
||||
|
||||
.choice-btn {
|
||||
padding: 0.45em 1em;
|
||||
border: var(--border-width) solid var(--primary);
|
||||
border-radius: var(--border-radius);
|
||||
background: transparent;
|
||||
color: var(--primary);
|
||||
font-size: 0.9em;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.choice-btn:hover:not(:disabled) {
|
||||
background: var(--primary);
|
||||
color: var(--primary-text);
|
||||
}
|
||||
|
||||
.choice-btn:active:not(:disabled) {
|
||||
transform: scale(0.97);
|
||||
color: var(--f1-bg);
|
||||
}
|
||||
|
||||
.choice-btn:disabled {
|
||||
@@ -1189,17 +1171,12 @@
|
||||
|
||||
.choice-btn.choice-selected {
|
||||
background: var(--primary);
|
||||
color: var(--primary-text);
|
||||
color: var(--f1-bg);
|
||||
border-color: var(--primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.choice-btn.choice-unselected {
|
||||
opacity: 0.4;
|
||||
opacity: var(--semi-transparent);
|
||||
border-color: var(--f1-border);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.choice-answered .choice-question {
|
||||
opacity: 0.7;
|
||||
}
|
||||
@@ -193,6 +193,10 @@
|
||||
<input type="checkbox" id="agentToolChoice">
|
||||
Tool-Nutzung erzwingen <span class="checkbox-hint">(tool_choice: any)</span>
|
||||
</label>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="agentAllowUserChoice">
|
||||
Rückfragen erlauben <span class="checkbox-hint">(ask_user_choice Tool)</span>
|
||||
</label>
|
||||
<label>Git-Commit-Verhalten</label>
|
||||
<select id="agentAutoCommit">
|
||||
<option value="">Nicht erwähnen</option>
|
||||
|
||||
@@ -18,6 +18,7 @@ registerPage('agent', {
|
||||
const descEl = document.getElementById('agentDescription');
|
||||
const modelEl = document.getElementById('agentModel');
|
||||
const toolChoiceEl = document.getElementById('agentToolChoice');
|
||||
const allowUserChoiceEl = document.getElementById('agentAllowUserChoice');
|
||||
const autoCommitEl = document.getElementById('agentAutoCommit');
|
||||
const useSoulEl = document.getElementById('agentUseSoul');
|
||||
const useIdentityEl = document.getElementById('agentUseIdentity');
|
||||
@@ -49,6 +50,7 @@ registerPage('agent', {
|
||||
descEl.value = agent.description || '';
|
||||
modelEl.value = agent.model || 'sonnet';
|
||||
toolChoiceEl.checked = (agent.toolChoice || 'any') === 'any';
|
||||
allowUserChoiceEl.checked = agent.allowUserChoice !== false;
|
||||
autoCommitEl.value = agent.autoCommit || '';
|
||||
useSoulEl.checked = agent.useSoul !== false;
|
||||
useIdentityEl.checked = agent.useIdentity !== false;
|
||||
@@ -94,6 +96,7 @@ registerPage('agent', {
|
||||
description: descEl.value.trim(),
|
||||
model: modelEl.value,
|
||||
toolChoice: toolChoiceEl.checked ? 'any' : 'auto',
|
||||
allowUserChoice: allowUserChoiceEl.checked,
|
||||
autoCommit: autoCommitEl.value,
|
||||
useSoul: useSoulEl.checked,
|
||||
useIdentity: useIdentityEl.checked,
|
||||
|
||||
Reference in new issue
Block a user