-
Notifications
You must be signed in to change notification settings - Fork 1
Fix GAgent durable terminal completion #657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
5ee463f
274df47
aee3b13
16eccf9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| namespace Aevatar.CQRS.Projection.Core.Abstractions; | ||
|
|
||
| /// <summary> | ||
| /// Durable materialization scope that is partitioned by an explicit session key. | ||
| /// </summary> | ||
| public interface IProjectionSessionScopedMaterializationContext : IProjectionMaterializationContext | ||
| { | ||
| string SessionId { get; } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| namespace Aevatar.GAgentService.Abstractions.ScopeGAgents; | ||
|
|
||
| public enum GAgentRunTerminalStatus | ||
| { | ||
| Unknown = 0, | ||
| TextMessageCompleted = 1, | ||
| RunFinished = 2, | ||
| Failed = 3, | ||
| } | ||
|
|
||
| public enum GAgentRunTerminalInteractionKind | ||
| { | ||
| Unknown = 0, | ||
| DraftRun = 1, | ||
| Approval = 2, | ||
| } | ||
|
|
||
| public sealed record GAgentRunTerminalSnapshot( | ||
| string ActorId, | ||
| string SessionId, | ||
| string CorrelationId, | ||
| GAgentRunTerminalInteractionKind InteractionKind, | ||
| GAgentRunTerminalStatus Status, | ||
| string ReasonCode, | ||
| string ReasonMessage, | ||
| long StateVersion, | ||
| string LastEventId, | ||
| DateTimeOffset ObservedAt); | ||
|
|
||
| public interface IGAgentRunTerminalQueryPort | ||
| { | ||
| Task<GAgentRunTerminalSnapshot?> GetByCorrelationIdAsync( | ||
| string actorId, | ||
| string correlationId, | ||
| CancellationToken ct = default); | ||
|
|
||
| Task<GAgentRunTerminalSnapshot?> GetBySessionIdAsync( | ||
| string actorId, | ||
| string sessionId, | ||
| CancellationToken ct = default); | ||
| } | ||
|
|
||
| public interface IGAgentRunTerminalProjectionLease | ||
| { | ||
| string ActorId { get; } | ||
|
|
||
| string CorrelationId { get; } | ||
|
|
||
| GAgentRunTerminalInteractionKind InteractionKind { get; } | ||
| } | ||
|
|
||
| public interface IGAgentRunTerminalProjectionPort | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Consensus: 2 models] severity=major, category=arch
Fix: return a lease (analogous to Per-model verbatim
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 16eccf9. IGAgentRunTerminalProjectionPort now returns an IGAgentRunTerminalProjectionLease and exposes ReleaseProjectionAsync. Draft-run and approval targets retain the terminal lease and release it during cleanup, including activation-failure cleanup after terminal materialization succeeds. |
||
| { | ||
| Task<IGAgentRunTerminalProjectionLease?> EnsureProjectionAsync( | ||
| string actorId, | ||
| string correlationId, | ||
| GAgentRunTerminalInteractionKind interactionKind, | ||
| CancellationToken ct = default); | ||
|
|
||
| Task ReleaseProjectionAsync( | ||
| IGAgentRunTerminalProjectionLease lease, | ||
| CancellationToken ct = default); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[kimi] severity=major, category=bug
The approval-denied
elsebranch callsPersistApprovalTerminalFailureAsyncwithout atry / catch. If this throws afterClearPendingApprovalEventis already persisted, the actor event fails and retries; on retryState.PendingApprovalis already null so the method returns early, permanently losing the terminal failure fact — exactly what the durable readmodel needs.The same gap exists in two more call sites in this file:
HandleToolApprovalTimeoutno-remote-handler branch (around line 195)HandleToolApprovalTimeoutremote-failed/denied/timed-out branch (around line 249)Only the exception path at lines 143-150 wraps it in
try { … } catch { /* best effort */ }.Fix: either wrap each call site in best-effort try/catch (matching the pattern at lines 143-150), or move the try/catch inside
PersistApprovalTerminalFailureAsyncitself so every caller is safe.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 16eccf9. Approval denied, no-remote timeout, and remote denied/failed/timed-out paths now persist the terminal failure fact before clearing PendingApproval, preserving the durable completion source if terminal persistence fails.