Skip to content

Commit 7a40208

Browse files
committed
Handle in-progress file change parser status
1 parent bd45271 commit 7a40208

5 files changed

Lines changed: 20 additions & 0 deletions

File tree

GeminiSharpSDK.Tests/Performance/ThreadEventParserPerformanceTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class ThreadEventParserPerformanceTests
1717
"""{"type":"result","status":"success","stats":{"input_tokens":10,"cached":3,"output_tokens":5}}""",
1818
"""{"type":"thread.started","thread_id":"legacy_thread"}""",
1919
"""{"type":"turn.failed","error":{"message":"legacy failed"}}""",
20+
"""{"type":"item.started","item":{"id":"file_1","type":"file_change","changes":[{"path":"src/app.cs","kind":"update"}],"status":"in_progress"}}""",
2021
"""{"type":"item.completed","item":{"id":"agent_1","type":"agent_message","text":"legacy text"}}""",
2122
];
2223

@@ -70,6 +71,7 @@ public async Task Parse_MixedSupportedEventStream_CompletesWithinBudgetAndCovers
7071
await Assert.That(eventKinds).Contains(typeof(ResultEvent).FullName!);
7172
await Assert.That(eventKinds).Contains(typeof(ThreadStartedEvent).FullName!);
7273
await Assert.That(eventKinds).Contains(typeof(TurnFailedEvent).FullName!);
74+
await Assert.That(eventKinds).Contains(typeof(ItemStartedEvent).FullName!);
7375
await Assert.That(eventKinds).Contains(typeof(ItemCompletedEvent).FullName!);
7476
await Assert.That(toolResultStatuses).IsEquivalentTo([ToolResultStatus.Success]);
7577
await Assert.That(assistantMessages).IsGreaterThan(0);

GeminiSharpSDK.Tests/Unit/ThreadEventParserTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ public async Task Parse_PreservesLegacyThreadStartedSupport()
6363
await Assert.That(parsed).IsTypeOf<ThreadStartedEvent>();
6464
}
6565

66+
[Test]
67+
public async Task Parse_ParsesFileChangeItemStartedWithInProgressStatus()
68+
{
69+
var parsed = (ItemStartedEvent)ThreadEventParser.Parse(
70+
"{\"type\":\"item.started\",\"item\":{\"id\":\"item_1\",\"type\":\"file_change\",\"changes\":[{\"path\":\"C:/git/GeminiSandbox/apple.txt\",\"kind\":\"add\"}],\"status\":\"in_progress\"}}");
71+
72+
await Assert.That(parsed.Item).IsTypeOf<FileChangeItem>();
73+
74+
var fileChange = (FileChangeItem)parsed.Item;
75+
await Assert.That(fileChange.Status).IsEqualTo(PatchApplyStatus.InProgress);
76+
await Assert.That(fileChange.Changes).Count().IsEqualTo(1);
77+
await Assert.That(fileChange.Changes[0].Path).IsEqualTo("C:/git/GeminiSandbox/apple.txt");
78+
await Assert.That(fileChange.Changes[0].Kind).IsEqualTo(PatchChangeKind.Add);
79+
}
80+
6681
[Test]
6782
public async Task Parse_ThrowsForUnsupportedEventType()
6883
{

GeminiSharpSDK/Internal/ThreadEventParser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ private static PatchApplyStatus ParsePatchApplyStatus(string status)
301301
{
302302
return status switch
303303
{
304+
GeminiProtocolConstants.Statuses.InProgress => PatchApplyStatus.InProgress,
304305
GeminiProtocolConstants.Statuses.Completed => PatchApplyStatus.Completed,
305306
GeminiProtocolConstants.Statuses.Failed => PatchApplyStatus.Failed,
306307
_ => throw new InvalidOperationException($"Unsupported patch apply status: {status}"),

GeminiSharpSDK/Models/Items.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public enum PatchChangeKind
2525

2626
public enum PatchApplyStatus
2727
{
28+
InProgress,
2829
Completed,
2930
Failed,
3031
}

docs/Features/thread-run-flow.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Provide deterministic thread-based execution over Gemini CLI so C# consumers can
4040
- Invalid JSONL event lines must fail fast with parse context.
4141
- Protocol tokens are parsed via constants, not inline literals.
4242
- Parser must support the current `init`, `message`, `tool_use`, `tool_result`, `error`, and `result` event envelope, while retaining compatibility with older persisted thread fixtures.
43+
- `file_change` items may surface before completion with `status=in_progress`; parser must accept in-progress, completed, and failed patch-apply states.
4344
- Optional `ILogger` (`Microsoft.Extensions.Logging`) receives process lifecycle diagnostics (start/success/failure/cancellation).
4445
- Structured output uses typed `StructuredOutputSchema` models that are embedded into the prompt contract and deserialized to typed DTOs; fenced JSON responses are normalized before deserialization.
4546
- `LocalImageInput` accepts image path, `FileInfo`, or `Stream`; stream inputs are materialized to temp files and referenced in the prompt as local `@path` inputs.

0 commit comments

Comments
 (0)