Opus 4.5+ and Sonnet 4.6+ support a new "effort" knob that controls how
much budget the model spends on thinking and tool calls. Plumb it through
end to end so each agent can pick its own level.
Storage & shape:
- New TEXT column agents.effort (default '') added via TryAddColumn.
- AgentRecord.Effort + INSERT/UPDATE in DatabaseService.Agents.cs.
- ChatContext.Effort + SubAgentContext.Effort so the value travels with the
request alongside model and tool settings.
Agent editor:
- Effort dropdown above git-commit behavior in the agent form (low/medium/
high/xhigh/max plus empty = "use default"). Always visible; on OpenAI
providers the value is sent but silently ignored.
- agent-page.js load/save and AgentEndpoint create/update wired up.
Anthropic API path:
- StreamChat and RunNonStreamingToolLoop add output_config: { effort } when
effort is set and not "high" – empty/null/"high" means "omit and let the
API pick its default".
- Sub-agents (preparer/review/finalizer) get the parameter through
RunAgentChat so each step uses its own agent's effort.
Anthropic CLI path:
- ClaudeCliService.ChatStreamingAsync takes an effort parameter and exports
CLAUDE_CODE_EFFORT_LEVEL on the spawned process. Env-var beats the
--effort flag because it also covers "max" and "ultracode".
- StreamChatViaCli, ChatNonStreamingViaCli, RunSubAgentViaCli, and the
ChatEndpoint anthropic branches all hand the value through.
ARCHITECTURE.md / ARCHITECTURE_QUICK.md updated with the new field.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
122 lines
5.3 KiB
C#
122 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Dapper;
|
|
using Gott.Models;
|
|
|
|
namespace Gott.Services;
|
|
|
|
public partial class DatabaseService
|
|
{
|
|
// ── Agents ──
|
|
|
|
public async Task<AgentRecord> CreateAgent(AgentRecord agent)
|
|
{
|
|
using var conn = CreateConnection();
|
|
var now = DateTime.UtcNow.ToString("o");
|
|
agent.AgentId = Guid.NewGuid().ToString("N");
|
|
agent.CreatedAt = now;
|
|
agent.UpdatedAt = now;
|
|
await conn.ExecuteAsync(@"
|
|
INSERT INTO agents (agent_id, user_id, name, avatar, avatar_small, description, model, tool_choice, custom_commands, auto_commit, use_soul, use_identity, use_user_info, use_memory, use_auto_context, use_github_search, use_serper_search, use_web_search, web_search_version, allow_user_choice, task_instruction, effort, avatar_scale, avatar_offset_x, avatar_offset_y, is_public, is_deleted, created_at, updated_at)
|
|
VALUES (@AgentId, @UserId, @Name, @Avatar, @AvatarSmall, @Description, @Model, @ToolChoice, @CustomCommands, @AutoCommit, @UseSoul, @UseIdentity, @UseUserInfo, @UseMemory, @UseAutoContext, @UseGitHubSearch, @UseSerperSearch, @UseWebSearch, @WebSearchVersion, @AllowUserChoice, @TaskInstruction, @Effort, @AvatarScale, @AvatarOffsetX, @AvatarOffsetY, @IsPublic, 0, @CreatedAt, @UpdatedAt)
|
|
", agent);
|
|
return agent;
|
|
}
|
|
|
|
public async Task<IEnumerable<AgentRecord>> GetAgents(string userId)
|
|
{
|
|
using var conn = CreateConnection();
|
|
return await conn.QueryAsync<AgentRecord>(
|
|
"SELECT * FROM agents WHERE user_id = @userId AND is_deleted = 0 ORDER BY name", new { userId });
|
|
}
|
|
|
|
public async Task<IEnumerable<AgentRecord>> GetAvailableAgents(string userId)
|
|
{
|
|
using var conn = CreateConnection();
|
|
return await conn.QueryAsync<AgentRecord>(
|
|
"SELECT * FROM agents WHERE (user_id = @userId OR is_public = 1) AND is_deleted = 0 ORDER BY name", new { userId });
|
|
}
|
|
|
|
public async Task<AgentRecord> GetAgent(string agentId)
|
|
{
|
|
using var conn = CreateConnection();
|
|
return await conn.QuerySingleOrDefaultAsync<AgentRecord>(
|
|
"SELECT * FROM agents WHERE agent_id = @agentId AND is_deleted = 0", new { agentId });
|
|
}
|
|
|
|
public async Task UpdateAgent(AgentRecord agent)
|
|
{
|
|
using var conn = CreateConnection();
|
|
agent.UpdatedAt = DateTime.UtcNow.ToString("o");
|
|
await conn.ExecuteAsync(@"
|
|
UPDATE agents SET name = @Name, avatar = @Avatar, avatar_small = @AvatarSmall, description = @Description,
|
|
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_auto_context = @UseAutoContext, use_github_search = @UseGitHubSearch, use_serper_search = @UseSerperSearch, use_web_search = @UseWebSearch, web_search_version = @WebSearchVersion,
|
|
allow_user_choice = @AllowUserChoice, task_instruction = @TaskInstruction, effort = @Effort,
|
|
avatar_scale = @AvatarScale, avatar_offset_x = @AvatarOffsetX, avatar_offset_y = @AvatarOffsetY,
|
|
is_public = @IsPublic, updated_at = @UpdatedAt
|
|
WHERE agent_id = @AgentId AND user_id = @UserId
|
|
", agent);
|
|
}
|
|
|
|
public async Task DeleteAgent(string agentId, string userId)
|
|
{
|
|
using var conn = CreateConnection();
|
|
await conn.ExecuteAsync(
|
|
"UPDATE agents SET is_deleted = 1, updated_at = @now WHERE agent_id = @agentId AND user_id = @userId",
|
|
new { agentId, userId, now = DateTime.UtcNow.ToString("o") });
|
|
}
|
|
|
|
|
|
// ── Agent Skills ──
|
|
|
|
public async Task<IEnumerable<string>> GetAgentSkills(string agentId)
|
|
{
|
|
using var conn = CreateConnection();
|
|
return await conn.QueryAsync<string>(
|
|
"SELECT skill_slug FROM agent_skills WHERE agent_id = @agentId ORDER BY skill_slug",
|
|
new { agentId });
|
|
}
|
|
|
|
public async Task SetAgentSkills(string agentId, IEnumerable<string> skillSlugs)
|
|
{
|
|
using var conn = CreateConnection();
|
|
using var tx = conn.BeginTransaction();
|
|
|
|
await conn.ExecuteAsync("DELETE FROM agent_skills WHERE agent_id = @agentId", new { agentId }, tx);
|
|
|
|
var now = DateTime.UtcNow.ToString("o");
|
|
foreach (var slug in skillSlugs)
|
|
{
|
|
await conn.ExecuteAsync(@"
|
|
INSERT INTO agent_skills (agent_id, skill_slug, created_at)
|
|
VALUES (@agentId, @slug, @now)",
|
|
new { agentId, slug, now }, tx);
|
|
}
|
|
|
|
tx.Commit();
|
|
}
|
|
|
|
public async Task AddAgentSkill(string agentId, string skillSlug)
|
|
{
|
|
using var conn = CreateConnection();
|
|
var now = DateTime.UtcNow.ToString("o");
|
|
await conn.ExecuteAsync(@"
|
|
INSERT OR IGNORE INTO agent_skills (agent_id, skill_slug, created_at)
|
|
VALUES (@agentId, @skillSlug, @now)",
|
|
new { agentId, skillSlug, now });
|
|
}
|
|
|
|
public async Task RemoveAgentSkill(string agentId, string skillSlug)
|
|
{
|
|
using var conn = CreateConnection();
|
|
await conn.ExecuteAsync(
|
|
"DELETE FROM agent_skills WHERE agent_id = @agentId AND skill_slug = @skillSlug",
|
|
new { agentId, skillSlug });
|
|
}
|
|
|
|
}
|