summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-11 21:59:27 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-11 21:59:27 +0900
commit6a9f90d0559f1ebf7967ab903f25d3e632d1f954 (patch)
treea02ba96ce41a29cc1c01d0990beee1f554c8e521
parent7c9794f8d4d05074b96bb525d19db4ee1f6b3e95 (diff)
Strengthen verified task execution prompts
-rw-r--r--doc/Design.md6
-rw-r--r--src/Agent.Core/Prompts/PromptComposer.cs21
-rw-r--r--src/Agent.Core/Runtime/AgentRuntime.cs2
-rw-r--r--tests/Agent.Core.Tests/PromptAndRuntimeTests.cs6
4 files changed, 32 insertions, 3 deletions
diff --git a/doc/Design.md b/doc/Design.md
index f8f5d0b..a637e3b 100644
--- a/doc/Design.md
+++ b/doc/Design.md
@@ -399,7 +399,11 @@ AgentSession
5. Sandbox capability summary
6. current TaskGraph / current Task
7. previous Summary
-8. recent Conversation / Execution Result
+8. recent verified Execution Result
+9. current Taskの`requires_external_effect`に基づく実行要件
+10. recent Conversation
+
+実行要件は、外部効果が必要なTaskでは文章上の宣言、計画、JSON例を実行済みと扱わず、対応するInternal Toolを直ちに呼び出すよう指示する。成功済みのread結果はExecution Resultから再利用し、不要な再読込を避けてwrite/processへ進む。外部効果が不要なTaskにはToolを強制しない。
### 9.3 Summary policy
`num_ctx`に対する利用率が設定閾値を超えたとき、古いConversation/Execution Resultを要約する。利用率 = latest `prompt_eval_count` / `num_ctx`(累積 InputTokens ではない)。既定閾値は80%とする。次は削除・曖昧化してはならない。
- 利用者が明示した制約
diff --git a/src/Agent.Core/Prompts/PromptComposer.cs b/src/Agent.Core/Prompts/PromptComposer.cs
index 69b18f3..2899088 100644
--- a/src/Agent.Core/Prompts/PromptComposer.cs
+++ b/src/Agent.Core/Prompts/PromptComposer.cs
@@ -13,8 +13,10 @@ public sealed record PromptContext(
string SandboxCapabilitySummary,
string TaskGraphSummary,
string PreviousSummary,
+ IReadOnlyList<ExecutionResult> ExecutionResults,
IReadOnlyList<ConversationMessage> Conversation,
string Request,
+ bool RequiresExternalEffect,
IReadOnlyList<string>? Images = null);
public static class PromptComposer
@@ -29,7 +31,9 @@ public static class PromptComposer
new("system", ComposeSkillCatalog(context.AvailableSkills)),
new("system", context.SandboxCapabilitySummary),
new("system", context.TaskGraphSummary),
- new("system", context.PreviousSummary)
+ new("system", context.PreviousSummary),
+ new("system", ComposeExecutionResults(context.ExecutionResults)),
+ new("system", ComposeExecutionRequirement(context.RequiresExternalEffect))
};
// Inject selected skill instructions (Progressive Disclosure Stage 3).
foreach (AgentSkill skill in context.SelectedSkills)
@@ -39,6 +43,21 @@ public static class PromptComposer
return messages;
}
+ private static string ComposeExecutionRequirement(bool requiresExternalEffect) => requiresExternalEffect
+ ? "The current Planner Task requires a verified external effect. Call the appropriate available Internal Tool now. " +
+ "A prose description, promise, plan, or fenced JSON example does not perform the operation and cannot complete this Task. " +
+ "After a successful read, use its returned content and proceed to the required write or process operation without repeating the read unnecessarily."
+ : "The current Planner Task does not require an external effect. Use an Internal Tool only when its verified result is needed; do not claim an unverified result.";
+
+ private static string ComposeExecutionResults(IReadOnlyList<ExecutionResult> results)
+ {
+ if (results.Count == 0) return "No prior Execution Results are available for the current Session.";
+ var lines = new List<string> { "Recent verified Execution Results:" };
+ foreach (ExecutionResult result in results)
+ lines.Add($"- {result.ToolName} ({(result.Success ? "success" : "failed")}): {result.Output}");
+ return string.Join("\n", lines);
+ }
+
/// <summary>
/// Stage 1 Discovery: only name + description are included. Full instructions are NOT included.
/// </summary>
diff --git a/src/Agent.Core/Runtime/AgentRuntime.cs b/src/Agent.Core/Runtime/AgentRuntime.cs
index bc9fc5e..f1c7186 100644
--- a/src/Agent.Core/Runtime/AgentRuntime.cs
+++ b/src/Agent.Core/Runtime/AgentRuntime.cs
@@ -218,8 +218,10 @@ public sealed class AgentRuntime(TaskRegistry registry, IOllamaClient ollama, Ag
settings.SandboxCapabilitySummary,
BuildTaskGraphSummary(graph, plannerTask),
session.Summary ?? string.Empty,
+ session.ExecutionResults,
session.Conversation,
plannerTask.Description,
+ plannerTask.RequiresExternalEffect,
task.Images)).ToList();
var guard = new ToolUseGuard(settings.SameFailureLimit);
diff --git a/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs b/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs
index 836ed5e..a40720f 100644
--- a/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs
+++ b/tests/Agent.Core.Tests/PromptAndRuntimeTests.cs
@@ -20,12 +20,16 @@ public sealed class PromptAndRuntimeTests
};
IReadOnlyList<OllamaMessage> messages = PromptComposer.Compose(new PromptContext(
"fixed", "user system", "ja", availableSkills, [], "capability", "graph", "summary",
+ [new ExecutionResult(Guid.NewGuid(), "file_read", true, "verified content")],
[new ConversationMessage("user", "old"), new ConversationMessage("assistant", "reply")],
- "new request", ["image"]));
+ "new request", true, ["image"]));
// Check that the skill catalog (name + description) is present, not the full instructions.
Assert.Contains(messages, m => m.Content.Contains("test-skill") && m.Content.Contains("A test skill."));
Assert.DoesNotContain(messages, m => m.Content == "skill instructions");
+ Assert.Contains(messages, m => m.Role == "system" && m.Content.Contains("requires a verified external effect", StringComparison.Ordinal));
+ Assert.Contains(messages, m => m.Role == "system" && m.Content.Contains("fenced JSON example does not perform", StringComparison.Ordinal));
+ Assert.Contains(messages, m => m.Role == "system" && m.Content.Contains("file_read (success): verified content", StringComparison.Ordinal));
Assert.Equal("system", messages[0].Role);
Assert.Equal("user", messages[^1].Role);
Assert.Equal(["image"], messages[^1].Images);