Add outline import feature; drop Dto naming, map entities at the API boundary
Services now return entities; endpoints (and the agent toolsets) map to *Response records instead of services building wire DTOs themselves. Also brings in the outline-import agent, MCP tool, ledger and web dialog that were already in progress on disk.
This commit is contained in:
@@ -29,7 +29,7 @@ public class NovelAgentService(
|
||||
|
||||
private readonly AgentOptions _options = options.Value;
|
||||
|
||||
public async Task<IReadOnlyList<ConversationSummaryDto>> ListConversationsAsync(
|
||||
public async Task<IReadOnlyList<ConversationSummaryResponse>> ListConversationsAsync(
|
||||
Guid projectId, CancellationToken ct = default)
|
||||
{
|
||||
logger.LogInformation("Listing agent conversations for project {ProjectId}", projectId);
|
||||
@@ -37,29 +37,18 @@ public class NovelAgentService(
|
||||
return await db.Conversations
|
||||
.Where(c => c.ProjectId == projectId)
|
||||
.OrderByDescending(c => c.UpdatedAt)
|
||||
.Select(c => new ConversationSummaryDto(c.Id, c.ProjectId, c.Title, c.Messages.Count, c.UpdatedAt))
|
||||
.Select(c => new ConversationSummaryResponse(c.Id, c.ProjectId, c.Title, c.Messages.Count, c.UpdatedAt))
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
|
||||
/// <summary>Null when no conversation has this id — a lookup miss is expected, not exceptional.</summary>
|
||||
public async Task<ConversationDto?> GetConversationAsync(Guid conversationId, CancellationToken ct = default)
|
||||
public async Task<AgentConversation?> GetConversationAsync(Guid conversationId, CancellationToken ct = default)
|
||||
{
|
||||
Guard.Default(conversationId, nameof(conversationId));
|
||||
|
||||
logger.LogInformation("Getting agent conversation {ConversationId}", conversationId);
|
||||
|
||||
var conversation = await FindConversationAsync(conversationId, ct);
|
||||
if (conversation is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ConversationDto(
|
||||
conversation.Id,
|
||||
conversation.ProjectId,
|
||||
conversation.Title,
|
||||
[.. conversation.Messages.OrderBy(m => m.Sequence).Select(ToDto)],
|
||||
conversation.UpdatedAt);
|
||||
return await FindConversationAsync(conversationId, ct);
|
||||
}
|
||||
|
||||
/// <summary>True if a conversation was deleted; false if no conversation had this id.</summary>
|
||||
@@ -84,7 +73,7 @@ public class NovelAgentService(
|
||||
/// Sends a message to the agent and runs it to completion, executing any tools it
|
||||
/// calls along the way. Returns the assistant's final turn.
|
||||
/// </summary>
|
||||
public async Task<AgentTurnDto> SendMessageAsync(
|
||||
public async Task<AgentMessage> SendMessageAsync(
|
||||
Guid projectId, SendAgentMessageRequest request, CancellationToken ct = default)
|
||||
{
|
||||
Guard.Default(projectId, nameof(projectId));
|
||||
@@ -109,7 +98,7 @@ public class NovelAgentService(
|
||||
|
||||
var systemPrompt = await BuildSystemPromptAsync(projectId, ct);
|
||||
var transcript = BuildTranscript(conversation);
|
||||
var toolCalls = new List<ToolCallDto>();
|
||||
var toolCalls = new List<ToolCallResponse>();
|
||||
var text = new StringBuilder();
|
||||
|
||||
for (var iteration = 0; iteration < _options.MaxIterations; iteration++)
|
||||
@@ -146,7 +135,7 @@ public class NovelAgentService(
|
||||
"Agent tool {Tool} on project {ProjectId} {Outcome}",
|
||||
call.Name, projectId, outcome.IsError ? "failed" : "succeeded");
|
||||
|
||||
toolCalls.Add(new ToolCallDto(call.Name, call.Input.ToString(), outcome.Content));
|
||||
toolCalls.Add(new ToolCallResponse(call.Name, call.Input.ToString(), outcome.Content));
|
||||
results.Add(new AgentToolResultBlock(call.Id, outcome.Content, outcome.IsError));
|
||||
}
|
||||
|
||||
@@ -170,7 +159,7 @@ public class NovelAgentService(
|
||||
toolCalls.Count > 0 ? JsonSerializer.Serialize(toolCalls, JsonOptions) : null,
|
||||
ct);
|
||||
|
||||
return new AgentTurnDto(conversation.Id, ToDto(reply));
|
||||
return reply;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -307,15 +296,6 @@ public class NovelAgentService(
|
||||
""";
|
||||
}
|
||||
|
||||
private static AgentMessageDto ToDto(AgentMessage message) => new(
|
||||
message.Id,
|
||||
message.Role,
|
||||
message.Content,
|
||||
message.ToolCallsJson is null
|
||||
? []
|
||||
: JsonSerializer.Deserialize<List<ToolCallDto>>(message.ToolCallsJson, JsonOptions) ?? [],
|
||||
message.CreatedAt);
|
||||
|
||||
/// <summary>Derives a conversation title from its opening message.</summary>
|
||||
private static string Summarise(string message)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user