-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDeterministicAgentTurnEngine.cs
More file actions
171 lines (160 loc) · 6.75 KB
/
DeterministicAgentTurnEngine.cs
File metadata and controls
171 lines (160 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System.Security.Cryptography;
using System.Text;
using DotPilot.Core.Features.ControlPlaneDomain;
using DotPilot.Core.Features.RuntimeCommunication;
using DotPilot.Core.Features.RuntimeFoundation;
using ManagedCode.Communication;
namespace DotPilot.Runtime.Features.RuntimeFoundation;
internal sealed class DeterministicAgentTurnEngine(TimeProvider timeProvider)
{
private const string ApprovalKeyword = "approval";
private const string PlanSummary =
"Prepared a local-first runtime plan with isolated orchestration, storage, and policy boundaries.";
private const string ExecuteSummary =
"Completed the deterministic runtime flow and produced the expected local session artifacts.";
private const string PendingApprovalSummary =
"Paused the deterministic runtime flow because the prompt requested an approval checkpoint.";
private const string ResumedExecutionSummary =
"Resumed the persisted runtime flow after approval and completed the pending execution step.";
private const string RejectedExecutionSummary =
"Stopped the persisted runtime flow because the approval checkpoint was rejected.";
private const string ReviewSummary =
"Reviewed the runtime output and prepared the local session summary for the next operator action.";
private const string PlanArtifact = "runtime-foundation.plan.md";
private const string ExecuteArtifact = "runtime-foundation.snapshot.json";
private const string ReviewArtifact = "runtime-foundation.review.md";
private const string ArtifactIdentityDelimiter = "|";
public Result<AgentTurnResult> Execute(AgentTurnRequest request)
{
if (string.IsNullOrWhiteSpace(request.Prompt))
{
return Result<AgentTurnResult>.Fail(RuntimeCommunicationProblems.InvalidPrompt());
}
if (request.ProviderStatus is not ProviderConnectionStatus.Available)
{
return Result<AgentTurnResult>.Fail(
RuntimeCommunicationProblems.ProviderUnavailable(
request.ProviderStatus,
ProviderToolchainNames.DeterministicClientDisplayName));
}
return request.Mode switch
{
AgentExecutionMode.Plan => Result<AgentTurnResult>.Succeed(
CreateResult(
request.SessionId,
request.AgentProfileId,
PlanSummary,
SessionPhase.Plan,
ApprovalState.NotRequired,
PlanArtifact,
ArtifactKind.Plan)),
AgentExecutionMode.Execute when RequiresApproval(request.Prompt) => Result<AgentTurnResult>.Succeed(
CreateResult(
request.SessionId,
request.AgentProfileId,
PendingApprovalSummary,
SessionPhase.Paused,
ApprovalState.Pending,
ExecuteArtifact,
ArtifactKind.Snapshot)),
AgentExecutionMode.Execute => Result<AgentTurnResult>.Succeed(
CreateResult(
request.SessionId,
request.AgentProfileId,
ExecuteSummary,
SessionPhase.Execute,
ApprovalState.NotRequired,
ExecuteArtifact,
ArtifactKind.Snapshot)),
AgentExecutionMode.Review => Result<AgentTurnResult>.Succeed(
CreateResult(
request.SessionId,
request.AgentProfileId,
ReviewSummary,
SessionPhase.Review,
ApprovalState.Approved,
ReviewArtifact,
ArtifactKind.Report)),
_ => Result<AgentTurnResult>.Fail(RuntimeCommunicationProblems.OrchestrationUnavailable()),
};
}
public AgentTurnResult Resume(AgentTurnRequest request, AgentTurnResumeRequest resumeRequest)
{
ArgumentNullException.ThrowIfNull(request);
ArgumentNullException.ThrowIfNull(resumeRequest);
return resumeRequest.ApprovalState switch
{
ApprovalState.Approved => CreateResult(
request.SessionId,
request.AgentProfileId,
ResumedExecutionSummary,
SessionPhase.Execute,
ApprovalState.Approved,
ExecuteArtifact,
ArtifactKind.Snapshot),
ApprovalState.Rejected => CreateResult(
request.SessionId,
request.AgentProfileId,
string.IsNullOrWhiteSpace(resumeRequest.Summary) ? RejectedExecutionSummary : resumeRequest.Summary,
SessionPhase.Failed,
ApprovalState.Rejected,
ReviewArtifact,
ArtifactKind.Report),
_ => CreateResult(
request.SessionId,
request.AgentProfileId,
PendingApprovalSummary,
SessionPhase.Paused,
ApprovalState.Pending,
ExecuteArtifact,
ArtifactKind.Snapshot),
};
}
public static bool RequiresApproval(string prompt)
{
return prompt.Contains(ApprovalKeyword, StringComparison.OrdinalIgnoreCase);
}
private AgentTurnResult CreateResult(
SessionId sessionId,
AgentProfileId agentProfileId,
string summary,
SessionPhase nextPhase,
ApprovalState approvalState,
string artifactName,
ArtifactKind artifactKind)
{
return new AgentTurnResult(
summary,
nextPhase,
approvalState,
[CreateArtifact(sessionId, agentProfileId, artifactName, artifactKind)]);
}
private ArtifactDescriptor CreateArtifact(
SessionId sessionId,
AgentProfileId agentProfileId,
string artifactName,
ArtifactKind artifactKind)
{
return new ArtifactDescriptor
{
Id = new ArtifactId(CreateDeterministicGuid(sessionId, artifactName, artifactKind)),
SessionId = sessionId,
AgentProfileId = agentProfileId,
Name = artifactName,
Kind = artifactKind,
RelativePath = artifactName,
CreatedAt = timeProvider.GetUtcNow(),
};
}
private static Guid CreateDeterministicGuid(SessionId sessionId, string artifactName, ArtifactKind artifactKind)
{
var rawIdentity = string.Join(
ArtifactIdentityDelimiter,
sessionId.ToString(),
artifactName,
artifactKind.ToString());
Span<byte> bytes = stackalloc byte[32];
SHA256.HashData(Encoding.UTF8.GetBytes(rawIdentity), bytes);
return new Guid(bytes[..16]);
}
}