Label chapter chips by kind, not raw number
Beats, tags, locations, open questions, and character/arc-stage responses that reference a chapter now carry a ChapterLabel/DisplayNumber alongside the raw Number, computed via the new ChapterDisplayNumberLookup. Front/back matter chips show their title; body chapters show "Chapter N: Title".
This commit is contained in:
@@ -28,6 +28,7 @@ public class NovelAgentToolset(
|
||||
CharacterService characters,
|
||||
CharacterArcService arcs,
|
||||
ChapterService chapters,
|
||||
ChapterDisplayNumberLookup chapterLabels,
|
||||
BeatService beats,
|
||||
TagService tags,
|
||||
LocationService locations,
|
||||
@@ -359,7 +360,14 @@ public class NovelAgentToolset(
|
||||
async (_, input, ct) =>
|
||||
{
|
||||
var tagId = JsonInput.RequiredGuid(input, "tag_id");
|
||||
return await OrNotFound(tags.GetReferencesAsync(tagId, ct), t => t.ToReferencesResponse(), "Tag", tagId);
|
||||
var tag = await tags.GetReferencesAsync(tagId, ct);
|
||||
if (tag is null)
|
||||
{
|
||||
return new ToolNotFound("Tag", tagId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(tag.NovelId, ct);
|
||||
return tag.ToReferencesResponse(displayNumbers);
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
@@ -378,7 +386,14 @@ public class NovelAgentToolset(
|
||||
async (_, input, ct) =>
|
||||
{
|
||||
var locationId = JsonInput.RequiredGuid(input, "location_id");
|
||||
return await OrNotFound(locations.GetReferencesAsync(locationId, ct), l => l.ToReferencesResponse(), "Location", locationId);
|
||||
var location = await locations.GetReferencesAsync(locationId, ct);
|
||||
if (location is null)
|
||||
{
|
||||
return new ToolNotFound("Location", locationId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(location.NovelId, ct);
|
||||
return location.ToReferencesResponse(displayNumbers);
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
@@ -503,14 +518,18 @@ public class NovelAgentToolset(
|
||||
new JsonSchemaBuilder()
|
||||
.Str("character_id", "Id of the character.", required: true)
|
||||
.Build(),
|
||||
async (_, input, ct) =>
|
||||
async (novelId, input, ct) =>
|
||||
{
|
||||
var characterId = JsonInput.RequiredGuid(input, "character_id");
|
||||
return await OrNotFound(
|
||||
beats.ListForCharacterAsync(characterId, ct),
|
||||
list => list.Select(b => b.ToCharacterBeatResponse(characterId)),
|
||||
"Character",
|
||||
characterId);
|
||||
var characterBeats = await beats.ListForCharacterAsync(characterId, ct);
|
||||
if (characterBeats is null)
|
||||
{
|
||||
return new ToolNotFound("Character", characterId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(novelId, ct);
|
||||
return characterBeats.Select(b =>
|
||||
b.ToCharacterBeatResponse(characterId, b.Chapter is null ? null : chapterLabels.LabelFor(b.Chapter, displayNumbers)));
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
@@ -600,12 +619,18 @@ public class NovelAgentToolset(
|
||||
.Str("character_id", "Narrow to questions about one character.")
|
||||
.Bool("include_resolved", "Include questions already settled. Defaults to false.")
|
||||
.Build(),
|
||||
async (novelId, input, ct) => (await questions.ListAsync(
|
||||
novelId,
|
||||
JsonInput.Guid(input, "chapter_id"),
|
||||
JsonInput.Guid(input, "character_id"),
|
||||
JsonInput.Bool(input, "include_resolved") ?? false,
|
||||
ct)).Select(q => q.ToResponse()));
|
||||
async (novelId, input, ct) =>
|
||||
{
|
||||
var list = await questions.ListAsync(
|
||||
novelId,
|
||||
JsonInput.Guid(input, "chapter_id"),
|
||||
JsonInput.Guid(input, "character_id"),
|
||||
JsonInput.Bool(input, "include_resolved") ?? false,
|
||||
ct);
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(novelId, ct);
|
||||
return list.Select(q => q.ToResponse(displayNumbers));
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
"raise_open_question",
|
||||
@@ -618,13 +643,24 @@ public class NovelAgentToolset(
|
||||
.Str("chapter_id", "The chapter outline this is about, if any.")
|
||||
.Str("character_id", "The character this is about, if any.")
|
||||
.Build(),
|
||||
async (novelId, input, ct) => await OrNotFound(questions.CreateAsync(
|
||||
novelId,
|
||||
new CreateOpenQuestionRequest(
|
||||
JsonInput.RequiredString(input, "question"),
|
||||
JsonInput.String(input, "detail"),
|
||||
JsonInput.Guid(input, "chapter_id"),
|
||||
JsonInput.Guid(input, "character_id")), ct), q => q.ToResponse(), "Novel", novelId));
|
||||
async (novelId, input, ct) =>
|
||||
{
|
||||
var question = await questions.CreateAsync(
|
||||
novelId,
|
||||
new CreateOpenQuestionRequest(
|
||||
JsonInput.RequiredString(input, "question"),
|
||||
JsonInput.String(input, "detail"),
|
||||
JsonInput.Guid(input, "chapter_id"),
|
||||
JsonInput.Guid(input, "character_id")), ct);
|
||||
|
||||
if (question is null)
|
||||
{
|
||||
return new ToolNotFound("Novel", novelId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(novelId, ct);
|
||||
return question.ToResponse(displayNumbers);
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
"resolve_open_question",
|
||||
@@ -638,11 +674,19 @@ public class NovelAgentToolset(
|
||||
async (_, input, ct) =>
|
||||
{
|
||||
var questionId = JsonInput.RequiredGuid(input, "question_id");
|
||||
return await OrNotFound(questions.ResolveAsync(
|
||||
var question = await questions.ResolveAsync(
|
||||
questionId,
|
||||
new ResolveOpenQuestionRequest(
|
||||
JsonInput.RequiredString(input, "resolution"),
|
||||
JsonInput.Bool(input, "append_to_notes") ?? false), ct), q => q.ToResponse(), "OpenQuestion", questionId);
|
||||
JsonInput.Bool(input, "append_to_notes") ?? false), ct);
|
||||
|
||||
if (question is null)
|
||||
{
|
||||
return new ToolNotFound("OpenQuestion", questionId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(question.NovelId, ct);
|
||||
return question.ToResponse(displayNumbers);
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
@@ -654,7 +698,14 @@ public class NovelAgentToolset(
|
||||
async (_, input, ct) =>
|
||||
{
|
||||
var questionId = JsonInput.RequiredGuid(input, "question_id");
|
||||
return await OrNotFound(questions.ReopenAsync(questionId, ct), q => q.ToResponse(), "OpenQuestion", questionId);
|
||||
var question = await questions.ReopenAsync(questionId, ct);
|
||||
if (question is null)
|
||||
{
|
||||
return new ToolNotFound("OpenQuestion", questionId);
|
||||
}
|
||||
|
||||
var displayNumbers = await chapterLabels.ForNovelAsync(question.NovelId, ct);
|
||||
return question.ToResponse(displayNumbers);
|
||||
});
|
||||
|
||||
yield return new AgentTool(
|
||||
|
||||
Reference in New Issue
Block a user