Forge
csharp4405de34
1using System.Diagnostics;
2using System.Text.Json;
3using AgentClientProtocol;
4
5var process = new Process
6{
7 StartInfo = new ProcessStartInfo
8 {
9 FileName = "gemini",
10 Arguments = "--experimental-acp",
11 UseShellExecute = false,
12 CreateNoWindow = true,
13 RedirectStandardOutput = true,
14 RedirectStandardInput = true,
15 },
16};
17
18try
19{
20 if (!process.Start())
21 {
22 throw new Exception("Failed to start agent proccess");
23 }
24
25 var client = new ExampleClient();
26 var connection = new ClientSideConnection(_ => client, process.StandardOutput, process.StandardInput);
27
28 connection.Open();
29
30 var initResult = await connection.InitializeAsync(new InitializeRequest
31 {
32 ProtocolVersion = 1,
33 ClientCapabilities = new ClientCapabilities
34 {
35 Fs = new FileSystemCapability
36 {
37 ReadTextFile = true,
38 WriteTextFile = true
39 }
40 }
41 });
42
43 Console.WriteLine($"✅ Connected to agent (protocol v{initResult.ProtocolVersion})");
44
45 var sessionResult = await connection.NewSessionAsync(new NewSessionRequest
46 {
47 Cwd = Directory.GetCurrentDirectory(),
48 McpServers = []
49 });
50
51 Console.WriteLine($"📝 Created session: {sessionResult.SessionId}");
52 Console.WriteLine("💬 User: Hello, agent!\n");
53 Console.Write(" ");
54
55 var promptResult = await connection.PromptAsync(new PromptRequest
56 {
57 SessionId = sessionResult.SessionId,
58 Prompt = [new TextContentBlock { Text = "Hello, agent!" }]
59 });
60
61 Console.WriteLine($"\n\n✅ Agent completed with: {promptResult.StopReason}");
62}
63catch (Exception ex)
64{
65 Console.Error.WriteLine($"[Client] Error: {ex}");
66}
67finally
68{
69 process.Kill();
70}
71
72class ExampleClient : IAcpClient
73{
74 public async ValueTask<RequestPermissionResponse> RequestPermissionAsync(RequestPermissionRequest request, CancellationToken cancellationToken = default)
75 {
76 var toolCallElement = (JsonElement)request.ToolCall;
77 var title = toolCallElement.GetProperty("title").GetString() ?? "Unknown";
78 Console.WriteLine($"\n🔐 Permission requested: {title}");
79
80 Console.WriteLine("\nOptions:");
81 for (int i = 0; i < request.Options.Length; i++)
82 {
83 var option = request.Options[i];
84 Console.WriteLine($" {i + 1}. {option.Name} ({option.Kind})");
85 }
86
87 while (true)
88 {
89 Console.Write("\nChoose an option: ");
90 var answer = Console.ReadLine()?.Trim();
91 if (int.TryParse(answer, out var optionIndex) && optionIndex >= 1 && optionIndex <= request.Options.Length)
92 {
93 return new RequestPermissionResponse
94 {
95 Outcome = new SelectedRequestPermissionOutcome { OptionId = request.Options[optionIndex - 1].OptionId }
96 };
97 }
98 else
99 {
100 Console.WriteLine("Invalid option. Please try again.");
101 }
102 }
103 }
104
105 public async ValueTask SessionNotificationAsync(SessionNotification notification, CancellationToken cancellationToken = default)
106 {
107 var update = notification.Update;
108 switch (update)
109 {
110 case AgentMessageChunkSessionUpdate agentMessage:
111 if (agentMessage.Content is TextContentBlock text)
112 {
113 Console.Write(text.Text);
114 }
115 else
116 {
117 Console.WriteLine($"[{agentMessage.Content.GetType().Name}]");
118 }
119 break;
120 case ToolCallSessionUpdate toolCall:
121 Console.WriteLine($"\n🔧 {toolCall.Title} ({toolCall.Status})");
122 break;
123 case ToolCallUpdateSessionUpdate toolCallUpdate:
124 Console.WriteLine($"\n🔧 Tool call `{toolCallUpdate.ToolCallId}` updated: {toolCallUpdate.Status}\n");
125 break;
126 case PlanSessionUpdate:
127 case AgentThoughtChunkSessionUpdate:
128 case UserMessageChunkSessionUpdate:
129 Console.WriteLine($"[{update.GetType().Name}]");
130 break;
131 default:
132 break;
133 }
134 }
135
136 public async ValueTask<WriteTextFileResponse> WriteTextFileAsync(WriteTextFileRequest request, CancellationToken cancellationToken = default)
137 {
138 Console.Error.WriteLine($"[Client] Write text file called with: {JsonSerializer.Serialize(request)}");
139 return new WriteTextFileResponse();
140 }
141
142 public async ValueTask<ReadTextFileResponse> ReadTextFileAsync(ReadTextFileRequest request, CancellationToken cancellationToken = default)
143 {
144 Console.Error.WriteLine($"[Client] Read text file called with: {JsonSerializer.Serialize(request)}");
145 return new ReadTextFileResponse { Content = "Mock file content" };
146 }
147
148 public ValueTask<CreateTerminalResponse> CreateTerminalAsync(CreateTerminalRequest request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
149 public ValueTask<TerminalOutputResponse> TerminalOutputAsync(TerminalOutputRequest request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
150 public ValueTask<ReleaseTerminalResponse> ReleaseTerminalAsync(ReleaseTerminalRequest request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
151 public ValueTask<WaitForTerminalExitResponse> WaitForTerminalExitAsync(WaitForTerminalExitRequest request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
152 public ValueTask<KillTerminalCommandResponse> KillTerminalCommandAsync(KillTerminalCommandRequest request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
153 public ValueTask<JsonElement> ExtMethodAsync(string method, JsonElement request, CancellationToken cancellationToken = default) => throw new NotImplementedException();
154 public ValueTask ExtNotificationAsync(string method, JsonElement notification, CancellationToken cancellationToken = default) => throw new NotImplementedException();
155}
View only · write via MCP/CIDE