This is an automated email from the ASF dual-hosted git repository.

dimuthuupe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/master by this push:
     new a7d3d1f52e Enabling jupyter cell execution support
a7d3d1f52e is described below

commit a7d3d1f52efc0c8b66e66761c09fa10d7663fa62
Author: Dimuthu Wannipurage <[email protected]>
AuthorDate: Thu Jul 18 05:24:12 2024 -0400

    Enabling jupyter cell execution support
---
 modules/agent-framework/airavata-agent/README.md   |  33 +-
 .../airavata-agent/agent-communication.proto       |  15 +
 modules/agent-framework/airavata-agent/agent.go    | 126 ++++-
 .../airavata-agent/jupyter/kernel.py               |  12 +
 .../protos/agent-communication.pb.go               | 627 ++++++++++++++-------
 .../service/controllers/AgentController.java       |  23 +-
 .../connection/service/handlers/AgentHandler.java  |  65 ++-
 .../service/models/JupyterExecutionAck.java        |   4 +
 .../service/models/JupyterExecutionRequest.java    |  40 ++
 .../service/models/JupyterExecutionResponse.java   |  41 ++
 .../src/main/proto/agent-communication.proto       |  15 +
 11 files changed, 762 insertions(+), 239 deletions(-)

diff --git a/modules/agent-framework/airavata-agent/README.md 
b/modules/agent-framework/airavata-agent/README.md
index 53ca7f6809..f8f4963f3e 100644
--- a/modules/agent-framework/airavata-agent/README.md
+++ b/modules/agent-framework/airavata-agent/README.md
@@ -36,7 +36,7 @@ env GOOS=linux GOARCH=amd64 go build
 
 
 ```
-POST http://localhost:18880/api/v1/agent/execute
+POST http://localhost:18880/api/v1/agent/executecommandrequest
 
 {
     "agentId": "agent1",
@@ -44,6 +44,37 @@ POST http://localhost:18880/api/v1/agent/execute
     "arguments": ["docker", "ps", "-a"]
 } 
 ```
+
+```
+http://localhost:18880/api/v1/agent/executejupyterrequest
+
+{
+    "sessionId": "session1",
+    "keepAlive": true,
+    "code": "print(4 + 5)",
+    "agentId": "agent3"
+} 
+
+Response
+
+{
+    "executionId": "22f02087-87cc-4e90-bc3b-3b969179c31b",
+    "error": null
+}
+```
+```
+http://localhost:18880/api/v1/agent/executejupyterresponse/22f02087-87cc-4e90-bc3b-3b969179c31b
+
+Response
+
+{
+    "executionId": "93d82c06-31e5-477f-a73a-760908a7a482",
+    "sessionId": null,
+    "responseString": "{\"result\":\"9\\n\"}\n",
+    "available": true
+}
+```
+
 ```
 POST http://localhost:18880/api/v1/agent/tunnel
 
diff --git a/modules/agent-framework/airavata-agent/agent-communication.proto 
b/modules/agent-framework/airavata-agent/agent-communication.proto
index 0e54285ebd..762471c700 100644
--- a/modules/agent-framework/airavata-agent/agent-communication.proto
+++ b/modules/agent-framework/airavata-agent/agent-communication.proto
@@ -25,6 +25,12 @@ message ContainerExecutionResponse {
   string responseString = 2;
 }
 
+message JupyterExecutionResponse {
+  string executionId = 1;
+  string sessionId = 2;
+  string responseString = 3;
+}
+
 message TerminateExecutionResponse {
   string status = 1;
   string description = 2;
@@ -44,6 +50,7 @@ message AgentMessage {
     CommandExecutionResponse commandExecutionResponse = 2;
     ContainerExecutionResponse containerExecutionResponse = 3;
     TerminateExecutionResponse terminateExecutionResponse = 4;
+    JupyterExecutionResponse jupyterExecutionResponse = 5;
   }
 }
 
@@ -75,6 +82,13 @@ message CommandExecutionRequest {
   string workingDir = 3;
 }
 
+message JupyterExecutionRequest {
+  string executionId = 1;
+  string sessionId = 2;
+  bool keepAlive = 3;
+  string code = 4;
+}
+
 message TerminateExecutionRequest {
   string executionId = 1;
 }
@@ -90,5 +104,6 @@ message ServerMessage {
     TerminateExecutionRequest terminateExecutionRequest = 3;
     KillAgentRequest killAgentRequest = 4;
     TunnelCreationRequest tunnelCreationRequest = 5;
+    JupyterExecutionRequest jupyterExecutionRequest = 6;
   }
 }
\ No newline at end of file
diff --git a/modules/agent-framework/airavata-agent/agent.go 
b/modules/agent-framework/airavata-agent/agent.go
index 5ad7ac3ea7..b2e82c1f40 100644
--- a/modules/agent-framework/airavata-agent/agent.go
+++ b/modules/agent-framework/airavata-agent/agent.go
@@ -8,7 +8,10 @@ import (
        "net"
        "os"
        "os/exec"
-
+       "net/http"
+       "io/ioutil"
+       "encoding/json"
+       "bytes"
        protos "airavata-agent/protos"
 
        "golang.org/x/crypto/ssh"
@@ -68,35 +71,98 @@ func main() {
                        }
                        log.Printf("Received message %s", in.Message)
                        switch x := in.GetMessage().(type) {
-                       case *protos.ServerMessage_CommandExecutionRequest:
-                               log.Printf("Recived a command execution 
request")
-                               executionId := 
x.CommandExecutionRequest.ExecutionId
-                               execArgs := x.CommandExecutionRequest.Arguments
-                               log.Printf("Execution id %s", executionId)
-                               cmd := exec.Command(execArgs[0], 
execArgs[1:]...)
-                               stdout, err := cmd.Output()
-                               if err != nil {
-                                       log.Fatalf(err.Error())
-                                       return
-                               }
-
-                               stdoutString := string(stdout)
-                               log.Printf("Execution output is %s", 
stdoutString)
-                               
-                               if err := 
stream.Send(&protos.AgentMessage{Message: 
-                                       
&protos.AgentMessage_CommandExecutionResponse{
-                                               CommandExecutionResponse: 
&protos.CommandExecutionResponse{ExecutionId: executionId, ResponseString: 
stdoutString}}}); err != nil {
-                                       log.Printf("Failed to send execution 
result to server: %v", err)
-                               } 
-
-                       case *protos.ServerMessage_TunnelCreationRequest:
-                               log.Printf("Received a tunnel creation request")
-                               host := x.TunnelCreationRequest.DestinationHost
-                               destPort := 
x.TunnelCreationRequest.DestinationPort
-                               srcPort := x.TunnelCreationRequest.SourcePort
-                               keyPath := x.TunnelCreationRequest.SshKeyPath
-                               sshUser := x.TunnelCreationRequest.SshUserName
-                               openRemoteTunnel(host, destPort, srcPort, 
sshUser, keyPath)
+                               case 
*protos.ServerMessage_CommandExecutionRequest:
+                                       log.Printf("Recived a command execution 
request")
+                                       executionId := 
x.CommandExecutionRequest.ExecutionId
+                                       execArgs := 
x.CommandExecutionRequest.Arguments
+                                       log.Printf("Execution id %s", 
executionId)
+                                       cmd := exec.Command(execArgs[0], 
execArgs[1:]...)
+                                       stdout, err := cmd.Output()
+                                       if err != nil {
+                                               log.Fatalf(err.Error())
+                                               return
+                                       }
+
+                                       stdoutString := string(stdout)
+                                       log.Printf("Execution output is %s", 
stdoutString)
+                                       
+                                       if err := 
stream.Send(&protos.AgentMessage{Message: 
+                                               
&protos.AgentMessage_CommandExecutionResponse{
+                                                       
CommandExecutionResponse: &protos.CommandExecutionResponse{ExecutionId: 
executionId, ResponseString: stdoutString}}}); err != nil {
+                                               log.Printf("Failed to send 
execution result to server: %v", err)
+                                       } 
+
+                               case 
*protos.ServerMessage_JupyterExecutionRequest:
+                                       log.Printf("Recived a jupyter execution 
request")
+                                       executionId := 
x.JupyterExecutionRequest.ExecutionId
+                                       sessionId := 
x.JupyterExecutionRequest.SessionId
+                                       code := x.JupyterExecutionRequest.Code
+                                       
+                                       url := "http://127.0.0.1:15000/start";
+                                       client := &http.Client{}
+                                       req, err := http.NewRequest("GET", url, 
nil)
+                                       if err != nil {
+                                               log.Printf("Failed to create 
the request start jupyter kernel: %v", err)
+                                       }
+                                       resp, err := client.Do(req)
+                                       if err != nil {
+                                               log.Printf("Failed to send the 
request start jupyter kernel: %v", err)
+                                       }
+                                       defer resp.Body.Close()
+
+                                       body, err := ioutil.ReadAll(resp.Body)
+                                       if err != nil {
+                                               log.Printf("Failed to read 
response for start jupyter kernel: %v", err)
+                                       }
+
+                                       url = "http://127.0.0.1:15000/execute";
+                                       data := map[string]string{
+                                               "code":  code,
+                                       }
+                                       jsonData, err := json.Marshal(data)
+
+                                       if err != nil {
+                                               log.Fatalf("Failed to marshal 
JSON: %v", err)
+                                       }
+
+                                       req, err = http.NewRequest("POST", url, 
bytes.NewBuffer(jsonData))
+                                       if err != nil {
+                                               log.Printf("Failed to create 
the request run jupyter kernel: %v", err)
+                                       }
+                                       req.Header.Set("Content-Type", 
"application/json")
+
+                                       client = &http.Client{}
+
+                                       resp, err = client.Do(req)
+                                       if err != nil {
+                                               log.Printf("Failed to send the 
request run jupyter kernel: %v", err)
+                                       }
+                                       defer resp.Body.Close()
+
+                                       body, err = ioutil.ReadAll(resp.Body)
+                                       if err != nil {
+                                               log.Printf("Failed to read 
response for run jupyter kernel: %v", err)
+                                       }
+
+                                       log.Println("Jupyter execution 
response")
+                                       jupyterResponse := string(body)
+
+
+                                       if err := 
stream.Send(&protos.AgentMessage{Message: 
+                                               
&protos.AgentMessage_JupyterExecutionResponse{
+                                                       
JupyterExecutionResponse: &protos.JupyterExecutionResponse{ExecutionId: 
executionId, ResponseString: jupyterResponse, SessionId: sessionId}}}); err != 
nil {
+                                               log.Printf("Failed to send 
jupyter execution result to server: %v", err)
+                                       }
+
+
+                               case 
*protos.ServerMessage_TunnelCreationRequest:
+                                       log.Printf("Received a tunnel creation 
request")
+                                       host := 
x.TunnelCreationRequest.DestinationHost
+                                       destPort := 
x.TunnelCreationRequest.DestinationPort
+                                       srcPort := 
x.TunnelCreationRequest.SourcePort
+                                       keyPath := 
x.TunnelCreationRequest.SshKeyPath
+                                       sshUser := 
x.TunnelCreationRequest.SshUserName
+                                       openRemoteTunnel(host, destPort, 
srcPort, sshUser, keyPath)
                        }
 
                }
diff --git a/modules/agent-framework/airavata-agent/jupyter/kernel.py 
b/modules/agent-framework/airavata-agent/jupyter/kernel.py
index 83886a1296..c3f9f19569 100644
--- a/modules/agent-framework/airavata-agent/jupyter/kernel.py
+++ b/modules/agent-framework/airavata-agent/jupyter/kernel.py
@@ -10,11 +10,17 @@ app = Flask(__name__)
 km = None
 kc = None
 
+kernel_running = False
+
 @app.route('/start', methods=['GET'])
 def start_kernel():
 
     global km
     global kc
+    global kernel_running
+
+    if kernel_running:
+        return
     # Create a new kernel manager
     km = KernelManager(kernel_name='python3')
     km.start_kernel()
@@ -25,6 +31,7 @@ def start_kernel():
 
     # Ensure the client is connected before executing code
     kc.wait_for_ready()
+    kernel_running = True
     return "Kernel started"
 
 @app.route('/execute', methods=['POST'])
@@ -73,9 +80,14 @@ def stop():
 
     global km
     global kc
+    global kernel_running
 
+    if not kernel_running:
+        return
+    
     kc.stop_channels()
     km.shutdown_kernel()
+    kernel_running = False
     return 'Kernel shutting down...'
 
 
diff --git 
a/modules/agent-framework/airavata-agent/protos/agent-communication.pb.go 
b/modules/agent-framework/airavata-agent/protos/agent-communication.pb.go
index 9212c8eb77..6f02d6716f 100644
--- a/modules/agent-framework/airavata-agent/protos/agent-communication.pb.go
+++ b/modules/agent-framework/airavata-agent/protos/agent-communication.pb.go
@@ -177,6 +177,69 @@ func (x *ContainerExecutionResponse) GetResponseString() 
string {
        return ""
 }
 
+type JupyterExecutionResponse struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ExecutionId    string `protobuf:"bytes,1,opt,name=executionId,proto3" 
json:"executionId,omitempty"`
+       SessionId      string `protobuf:"bytes,2,opt,name=sessionId,proto3" 
json:"sessionId,omitempty"`
+       ResponseString string 
`protobuf:"bytes,3,opt,name=responseString,proto3" 
json:"responseString,omitempty"`
+}
+
+func (x *JupyterExecutionResponse) Reset() {
+       *x = JupyterExecutionResponse{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_agent_communication_proto_msgTypes[3]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *JupyterExecutionResponse) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JupyterExecutionResponse) ProtoMessage() {}
+
+func (x *JupyterExecutionResponse) ProtoReflect() protoreflect.Message {
+       mi := &file_agent_communication_proto_msgTypes[3]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use JupyterExecutionResponse.ProtoReflect.Descriptor instead.
+func (*JupyterExecutionResponse) Descriptor() ([]byte, []int) {
+       return file_agent_communication_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *JupyterExecutionResponse) GetExecutionId() string {
+       if x != nil {
+               return x.ExecutionId
+       }
+       return ""
+}
+
+func (x *JupyterExecutionResponse) GetSessionId() string {
+       if x != nil {
+               return x.SessionId
+       }
+       return ""
+}
+
+func (x *JupyterExecutionResponse) GetResponseString() string {
+       if x != nil {
+               return x.ResponseString
+       }
+       return ""
+}
+
 type TerminateExecutionResponse struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
@@ -189,7 +252,7 @@ type TerminateExecutionResponse struct {
 func (x *TerminateExecutionResponse) Reset() {
        *x = TerminateExecutionResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[3]
+               mi := &file_agent_communication_proto_msgTypes[4]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -202,7 +265,7 @@ func (x *TerminateExecutionResponse) String() string {
 func (*TerminateExecutionResponse) ProtoMessage() {}
 
 func (x *TerminateExecutionResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[3]
+       mi := &file_agent_communication_proto_msgTypes[4]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -215,7 +278,7 @@ func (x *TerminateExecutionResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TerminateExecutionResponse.ProtoReflect.Descriptor instead.
 func (*TerminateExecutionResponse) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{3}
+       return file_agent_communication_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *TerminateExecutionResponse) GetStatus() string {
@@ -243,7 +306,7 @@ type TunnelCreationResponse struct {
 func (x *TunnelCreationResponse) Reset() {
        *x = TunnelCreationResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[4]
+               mi := &file_agent_communication_proto_msgTypes[5]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -256,7 +319,7 @@ func (x *TunnelCreationResponse) String() string {
 func (*TunnelCreationResponse) ProtoMessage() {}
 
 func (x *TunnelCreationResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[4]
+       mi := &file_agent_communication_proto_msgTypes[5]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -269,7 +332,7 @@ func (x *TunnelCreationResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TunnelCreationResponse.ProtoReflect.Descriptor instead.
 func (*TunnelCreationResponse) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{4}
+       return file_agent_communication_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *TunnelCreationResponse) GetStatus() string {
@@ -290,7 +353,7 @@ type TunnelTerminationResponse struct {
 func (x *TunnelTerminationResponse) Reset() {
        *x = TunnelTerminationResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[5]
+               mi := &file_agent_communication_proto_msgTypes[6]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -303,7 +366,7 @@ func (x *TunnelTerminationResponse) String() string {
 func (*TunnelTerminationResponse) ProtoMessage() {}
 
 func (x *TunnelTerminationResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[5]
+       mi := &file_agent_communication_proto_msgTypes[6]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -316,7 +379,7 @@ func (x *TunnelTerminationResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TunnelTerminationResponse.ProtoReflect.Descriptor instead.
 func (*TunnelTerminationResponse) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{5}
+       return file_agent_communication_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *TunnelTerminationResponse) GetStatus() string {
@@ -337,13 +400,14 @@ type AgentMessage struct {
        //      *AgentMessage_CommandExecutionResponse
        //      *AgentMessage_ContainerExecutionResponse
        //      *AgentMessage_TerminateExecutionResponse
+       //      *AgentMessage_JupyterExecutionResponse
        Message isAgentMessage_Message `protobuf_oneof:"message"`
 }
 
 func (x *AgentMessage) Reset() {
        *x = AgentMessage{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[6]
+               mi := &file_agent_communication_proto_msgTypes[7]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -356,7 +420,7 @@ func (x *AgentMessage) String() string {
 func (*AgentMessage) ProtoMessage() {}
 
 func (x *AgentMessage) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[6]
+       mi := &file_agent_communication_proto_msgTypes[7]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -369,7 +433,7 @@ func (x *AgentMessage) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use AgentMessage.ProtoReflect.Descriptor instead.
 func (*AgentMessage) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{6}
+       return file_agent_communication_proto_rawDescGZIP(), []int{7}
 }
 
 func (m *AgentMessage) GetMessage() isAgentMessage_Message {
@@ -407,6 +471,13 @@ func (x *AgentMessage) GetTerminateExecutionResponse() 
*TerminateExecutionRespon
        return nil
 }
 
+func (x *AgentMessage) GetJupyterExecutionResponse() *JupyterExecutionResponse 
{
+       if x, ok := x.GetMessage().(*AgentMessage_JupyterExecutionResponse); ok 
{
+               return x.JupyterExecutionResponse
+       }
+       return nil
+}
+
 type isAgentMessage_Message interface {
        isAgentMessage_Message()
 }
@@ -427,6 +498,10 @@ type AgentMessage_TerminateExecutionResponse struct {
        TerminateExecutionResponse *TerminateExecutionResponse 
`protobuf:"bytes,4,opt,name=terminateExecutionResponse,proto3,oneof"`
 }
 
+type AgentMessage_JupyterExecutionResponse struct {
+       JupyterExecutionResponse *JupyterExecutionResponse 
`protobuf:"bytes,5,opt,name=jupyterExecutionResponse,proto3,oneof"`
+}
+
 func (*AgentMessage_AgentPing) isAgentMessage_Message() {}
 
 func (*AgentMessage_CommandExecutionResponse) isAgentMessage_Message() {}
@@ -435,6 +510,8 @@ func (*AgentMessage_ContainerExecutionResponse) 
isAgentMessage_Message() {}
 
 func (*AgentMessage_TerminateExecutionResponse) isAgentMessage_Message() {}
 
+func (*AgentMessage_JupyterExecutionResponse) isAgentMessage_Message() {}
+
 type ContainerExecutionRequest struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
@@ -449,7 +526,7 @@ type ContainerExecutionRequest struct {
 func (x *ContainerExecutionRequest) Reset() {
        *x = ContainerExecutionRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[7]
+               mi := &file_agent_communication_proto_msgTypes[8]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -462,7 +539,7 @@ func (x *ContainerExecutionRequest) String() string {
 func (*ContainerExecutionRequest) ProtoMessage() {}
 
 func (x *ContainerExecutionRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[7]
+       mi := &file_agent_communication_proto_msgTypes[8]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -475,7 +552,7 @@ func (x *ContainerExecutionRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use ContainerExecutionRequest.ProtoReflect.Descriptor instead.
 func (*ContainerExecutionRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{7}
+       return file_agent_communication_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *ContainerExecutionRequest) GetExecutionId() string {
@@ -522,7 +599,7 @@ type TunnelCreationRequest struct {
 func (x *TunnelCreationRequest) Reset() {
        *x = TunnelCreationRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[8]
+               mi := &file_agent_communication_proto_msgTypes[9]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -535,7 +612,7 @@ func (x *TunnelCreationRequest) String() string {
 func (*TunnelCreationRequest) ProtoMessage() {}
 
 func (x *TunnelCreationRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[8]
+       mi := &file_agent_communication_proto_msgTypes[9]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -548,7 +625,7 @@ func (x *TunnelCreationRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TunnelCreationRequest.ProtoReflect.Descriptor instead.
 func (*TunnelCreationRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{8}
+       return file_agent_communication_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *TunnelCreationRequest) GetDestinationHost() string {
@@ -606,7 +683,7 @@ type TunnelTerminationRequest struct {
 func (x *TunnelTerminationRequest) Reset() {
        *x = TunnelTerminationRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[9]
+               mi := &file_agent_communication_proto_msgTypes[10]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -619,7 +696,7 @@ func (x *TunnelTerminationRequest) String() string {
 func (*TunnelTerminationRequest) ProtoMessage() {}
 
 func (x *TunnelTerminationRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[9]
+       mi := &file_agent_communication_proto_msgTypes[10]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -632,7 +709,7 @@ func (x *TunnelTerminationRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TunnelTerminationRequest.ProtoReflect.Descriptor instead.
 func (*TunnelTerminationRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{9}
+       return file_agent_communication_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *TunnelTerminationRequest) GetDestinationHost() string {
@@ -669,7 +746,7 @@ type CommandExecutionRequest struct {
 func (x *CommandExecutionRequest) Reset() {
        *x = CommandExecutionRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[10]
+               mi := &file_agent_communication_proto_msgTypes[11]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -682,7 +759,7 @@ func (x *CommandExecutionRequest) String() string {
 func (*CommandExecutionRequest) ProtoMessage() {}
 
 func (x *CommandExecutionRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[10]
+       mi := &file_agent_communication_proto_msgTypes[11]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -695,7 +772,7 @@ func (x *CommandExecutionRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use CommandExecutionRequest.ProtoReflect.Descriptor instead.
 func (*CommandExecutionRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{10}
+       return file_agent_communication_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *CommandExecutionRequest) GetExecutionId() string {
@@ -719,6 +796,77 @@ func (x *CommandExecutionRequest) GetWorkingDir() string {
        return ""
 }
 
+type JupyterExecutionRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       ExecutionId string `protobuf:"bytes,1,opt,name=executionId,proto3" 
json:"executionId,omitempty"`
+       SessionId   string `protobuf:"bytes,2,opt,name=sessionId,proto3" 
json:"sessionId,omitempty"`
+       KeepAlive   bool   `protobuf:"varint,3,opt,name=keepAlive,proto3" 
json:"keepAlive,omitempty"`
+       Code        string `protobuf:"bytes,4,opt,name=code,proto3" 
json:"code,omitempty"`
+}
+
+func (x *JupyterExecutionRequest) Reset() {
+       *x = JupyterExecutionRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_agent_communication_proto_msgTypes[12]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *JupyterExecutionRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*JupyterExecutionRequest) ProtoMessage() {}
+
+func (x *JupyterExecutionRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_agent_communication_proto_msgTypes[12]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use JupyterExecutionRequest.ProtoReflect.Descriptor instead.
+func (*JupyterExecutionRequest) Descriptor() ([]byte, []int) {
+       return file_agent_communication_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *JupyterExecutionRequest) GetExecutionId() string {
+       if x != nil {
+               return x.ExecutionId
+       }
+       return ""
+}
+
+func (x *JupyterExecutionRequest) GetSessionId() string {
+       if x != nil {
+               return x.SessionId
+       }
+       return ""
+}
+
+func (x *JupyterExecutionRequest) GetKeepAlive() bool {
+       if x != nil {
+               return x.KeepAlive
+       }
+       return false
+}
+
+func (x *JupyterExecutionRequest) GetCode() string {
+       if x != nil {
+               return x.Code
+       }
+       return ""
+}
+
 type TerminateExecutionRequest struct {
        state         protoimpl.MessageState
        sizeCache     protoimpl.SizeCache
@@ -730,7 +878,7 @@ type TerminateExecutionRequest struct {
 func (x *TerminateExecutionRequest) Reset() {
        *x = TerminateExecutionRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[11]
+               mi := &file_agent_communication_proto_msgTypes[13]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -743,7 +891,7 @@ func (x *TerminateExecutionRequest) String() string {
 func (*TerminateExecutionRequest) ProtoMessage() {}
 
 func (x *TerminateExecutionRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[11]
+       mi := &file_agent_communication_proto_msgTypes[13]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -756,7 +904,7 @@ func (x *TerminateExecutionRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use TerminateExecutionRequest.ProtoReflect.Descriptor instead.
 func (*TerminateExecutionRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{11}
+       return file_agent_communication_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *TerminateExecutionRequest) GetExecutionId() string {
@@ -777,7 +925,7 @@ type KillAgentRequest struct {
 func (x *KillAgentRequest) Reset() {
        *x = KillAgentRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[12]
+               mi := &file_agent_communication_proto_msgTypes[14]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -790,7 +938,7 @@ func (x *KillAgentRequest) String() string {
 func (*KillAgentRequest) ProtoMessage() {}
 
 func (x *KillAgentRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[12]
+       mi := &file_agent_communication_proto_msgTypes[14]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -803,7 +951,7 @@ func (x *KillAgentRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use KillAgentRequest.ProtoReflect.Descriptor instead.
 func (*KillAgentRequest) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{12}
+       return file_agent_communication_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *KillAgentRequest) GetReason() string {
@@ -825,13 +973,14 @@ type ServerMessage struct {
        //      *ServerMessage_TerminateExecutionRequest
        //      *ServerMessage_KillAgentRequest
        //      *ServerMessage_TunnelCreationRequest
+       //      *ServerMessage_JupyterExecutionRequest
        Message isServerMessage_Message `protobuf_oneof:"message"`
 }
 
 func (x *ServerMessage) Reset() {
        *x = ServerMessage{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_agent_communication_proto_msgTypes[13]
+               mi := &file_agent_communication_proto_msgTypes[15]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -844,7 +993,7 @@ func (x *ServerMessage) String() string {
 func (*ServerMessage) ProtoMessage() {}
 
 func (x *ServerMessage) ProtoReflect() protoreflect.Message {
-       mi := &file_agent_communication_proto_msgTypes[13]
+       mi := &file_agent_communication_proto_msgTypes[15]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -857,7 +1006,7 @@ func (x *ServerMessage) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use ServerMessage.ProtoReflect.Descriptor instead.
 func (*ServerMessage) Descriptor() ([]byte, []int) {
-       return file_agent_communication_proto_rawDescGZIP(), []int{13}
+       return file_agent_communication_proto_rawDescGZIP(), []int{15}
 }
 
 func (m *ServerMessage) GetMessage() isServerMessage_Message {
@@ -902,6 +1051,13 @@ func (x *ServerMessage) GetTunnelCreationRequest() 
*TunnelCreationRequest {
        return nil
 }
 
+func (x *ServerMessage) GetJupyterExecutionRequest() *JupyterExecutionRequest {
+       if x, ok := x.GetMessage().(*ServerMessage_JupyterExecutionRequest); ok 
{
+               return x.JupyterExecutionRequest
+       }
+       return nil
+}
+
 type isServerMessage_Message interface {
        isServerMessage_Message()
 }
@@ -926,6 +1082,10 @@ type ServerMessage_TunnelCreationRequest struct {
        TunnelCreationRequest *TunnelCreationRequest 
`protobuf:"bytes,5,opt,name=tunnelCreationRequest,proto3,oneof"`
 }
 
+type ServerMessage_JupyterExecutionRequest struct {
+       JupyterExecutionRequest *JupyterExecutionRequest 
`protobuf:"bytes,6,opt,name=jupyterExecutionRequest,proto3,oneof"`
+}
+
 func (*ServerMessage_ContainerExecutionRequest) isServerMessage_Message() {}
 
 func (*ServerMessage_CommandExecutionRequest) isServerMessage_Message() {}
@@ -936,6 +1096,8 @@ func (*ServerMessage_KillAgentRequest) 
isServerMessage_Message() {}
 
 func (*ServerMessage_TunnelCreationRequest) isServerMessage_Message() {}
 
+func (*ServerMessage_JupyterExecutionRequest) isServerMessage_Message() {}
+
 var File_agent_communication_proto protoreflect.FileDescriptor
 
 var file_agent_communication_proto_rawDesc = []byte{
@@ -957,145 +1119,176 @@ var file_agent_communication_proto_rawDesc = []byte{
        0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 
0x75, 0x74, 0x69, 0x6f,
        0x6e, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 
0x6e, 0x73, 0x65, 0x53,
        0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x0e, 0x72, 0x65, 0x73,
-       0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 
0x56, 0x0a, 0x1a, 0x54,
-       0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 
0x75, 0x74, 0x69, 0x6f,
-       0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 
0x06, 0x73, 0x74, 0x61,
-       0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 
0x74, 0x61, 0x74, 0x75,
-       0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 
0x74, 0x69, 0x6f, 0x6e,
-       0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 
0x72, 0x69, 0x70, 0x74,
-       0x69, 0x6f, 0x6e, 0x22, 0x30, 0x0a, 0x16, 0x54, 0x75, 0x6e, 0x6e, 0x65, 
0x6c, 0x43, 0x72, 0x65,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x12, 0x16, 0x0a,
-       0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x06, 0x73,
-       0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x33, 0x0a, 0x19, 0x54, 0x75, 0x6e, 
0x6e, 0x65, 0x6c, 0x54,
-       0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
+       0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 
0x82, 0x01, 0x0a, 0x18,
+       0x4a, 0x75, 0x70, 0x79, 0x74, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
+       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 
0x65, 0x78, 0x65, 0x63,
+       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x0b, 0x65,
+       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1c, 
0x0a, 0x09, 0x73, 0x65,
+       0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x09, 0x73,
+       0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 
0x72, 0x65, 0x73, 0x70,
+       0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x03, 
0x20, 0x01, 0x28, 0x09,
+       0x52, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x74, 
0x72, 0x69, 0x6e, 0x67,
+       0x22, 0x56, 0x0a, 0x1a, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 
0x65, 0x45, 0x78, 0x65,
+       0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 
0x73, 0x65, 0x12, 0x16,
+       0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x06,
+       0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 
0x73, 0x63, 0x72, 0x69,
+       0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x0b, 0x64, 0x65, 0x73,
+       0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x30, 0x0a, 0x16, 
0x54, 0x75, 0x6e, 0x6e,
+       0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
        0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 
0x18, 0x01, 0x20, 0x01,
-       0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc4, 
0x03, 0x0a, 0x0c, 0x41,
-       0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 
0x44, 0x0a, 0x09, 0x61,
-       0x67, 0x65, 0x6e, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 
0x28, 0x0b, 0x32, 0x24,
-       0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 
0x61, 0x69, 0x72, 0x61,
-       0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 
0x67, 0x65, 0x6e, 0x74,
-       0x50, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x09, 0x61, 0x67, 0x65, 0x6e, 
0x74, 0x50, 0x69, 0x6e,
-       0x67, 0x12, 0x71, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 
0x45, 0x78, 0x65, 0x63,
-       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x18, 0x02, 0x20,
-       0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 
0x61, 0x63, 0x68, 0x65,
+       0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x33, 
0x0a, 0x19, 0x54, 0x75,
+       0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 
0x69, 0x6f, 0x6e, 0x52,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 
0x74, 0x61, 0x74, 0x75,
+       0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 
0x74, 0x75, 0x73, 0x22,
+       0xb7, 0x04, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 
0x73, 0x61, 0x67, 0x65,
+       0x12, 0x44, 0x0a, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x69, 0x6e, 
0x67, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 
0x61, 0x63, 0x68, 0x65,
        0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 
0x65, 0x6e, 0x74, 0x2e,
-       0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
-       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x18, 
0x63, 0x6f, 0x6d, 0x6d,
-       0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 
0x52, 0x65, 0x73, 0x70,
-       0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 
0x61, 0x69, 0x6e, 0x65,
-       0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
-       0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6f, 
0x72, 0x67, 0x2e, 0x61,
+       0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 
0x09, 0x61, 0x67, 0x65,
+       0x6e, 0x74, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x71, 0x0a, 0x18, 0x63, 0x6f, 
0x6d, 0x6d, 0x61, 0x6e,
+       0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
+       0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x6f, 
0x72, 0x67, 0x2e, 0x61,
        0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 
0x74, 0x61, 0x2e, 0x61,
-       0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 
0x65, 0x72, 0x45, 0x78,
-       0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 
0x6e, 0x73, 0x65, 0x48,
-       0x00, 0x52, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 
0x45, 0x78, 0x65, 0x63,
-       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x12, 0x77, 0x0a,
+       0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 
0x45, 0x78, 0x65, 0x63,
+       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x48, 0x00, 0x52,
+       0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 
0x75, 0x74, 0x69, 0x6f,
+       0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 
0x1a, 0x63, 0x6f, 0x6e,
+       0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 
0x69, 0x6f, 0x6e, 0x52,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 
0x0b, 0x32, 0x35, 0x2e,
+       0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 
0x69, 0x72, 0x61, 0x76,
+       0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 
0x6e, 0x74, 0x61, 0x69,
+       0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 
0x52, 0x65, 0x73, 0x70,
+       0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 
0x61, 0x69, 0x6e, 0x65,
+       0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
+       0x73, 0x65, 0x12, 0x77, 0x0a, 0x1a, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 
0x61, 0x74, 0x65, 0x45,
+       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 
0x6f, 0x6e, 0x73, 0x65,
+       0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6f, 0x72, 0x67, 
0x2e, 0x61, 0x70, 0x61,
+       0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 
0x2e, 0x61, 0x67, 0x65,
+       0x6e, 0x74, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 
0x45, 0x78, 0x65, 0x63,
+       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x48, 0x00, 0x52,
        0x1a, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 
0x65, 0x63, 0x75, 0x74,
-       0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 
0x04, 0x20, 0x01, 0x28,
-       0x0b, 0x32, 0x35, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2e, 0x61,
-       0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 
0x74, 0x2e, 0x54, 0x65,
-       0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
-       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x1a, 
0x74, 0x65, 0x72, 0x6d,
-       0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 
0x6f, 0x6e, 0x52, 0x65,
-       0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 
0x73, 0x73, 0x61, 0x67,
-       0x65, 0x22, 0x9f, 0x01, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 
0x6e, 0x65, 0x72, 0x45,
+       0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 
0x71, 0x0a, 0x18, 0x6a,
+       0x75, 0x70, 0x79, 0x74, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 
0x69, 0x6f, 0x6e, 0x52,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 
0x0b, 0x32, 0x33, 0x2e,
+       0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 
0x69, 0x72, 0x61, 0x76,
+       0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4a, 0x75, 
0x70, 0x79, 0x74, 0x65,
+       0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
+       0x73, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6a, 0x75, 0x70, 0x79, 0x74, 0x65, 
0x72, 0x45, 0x78, 0x65,
+       0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 
0x73, 0x65, 0x42, 0x09,
+       0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x9f, 0x01, 
0x0a, 0x19, 0x43, 0x6f,
+       0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
+       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 
0x78, 0x65, 0x63, 0x75,
+       0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x0b, 0x65, 0x78,
+       0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a, 
0x0d, 0x63, 0x6f, 0x6e,
+       0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 
0x20, 0x01, 0x28, 0x09,
+       0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 
0x61, 0x6d, 0x65, 0x12,
+       0x1c, 0x0a, 0x09, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 
0x18, 0x03, 0x20, 0x03,
+       0x28, 0x09, 0x52, 0x09, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 
0x73, 0x12, 0x1c, 0x0a,
+       0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x18, 0x04, 
0x20, 0x01, 0x28, 0x09,
+       0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x22, 
0xe9, 0x01, 0x0a, 0x15,
+       0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 
0x74, 0x69, 0x6e, 0x61,
+       0x74, 0x69, 0x6f, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x0f,
+       0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 
0x6f, 0x73, 0x74, 0x12,
+       0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x50, 0x6f,
+       0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 
0x73, 0x74, 0x69, 0x6e,
+       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 
0x0b, 0x73, 0x73, 0x68,
+       0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x0b,
+       0x73, 0x73, 0x68, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 
0x1e, 0x0a, 0x0a, 0x73,
+       0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 
0x1e, 0x0a, 0x0a, 0x73,
+       0x73, 0x68, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x0a, 0x73, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 
0x1a, 0x0a, 0x08, 0x70,
+       0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x08, 0x70,
+       0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x8e, 0x01, 0x0a, 0x18, 
0x54, 0x75, 0x6e, 0x6e,
+       0x65, 0x6c, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 
0x6e, 0x52, 0x65, 0x71,
+       0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 
0x69, 0x6e, 0x61, 0x74,
+       0x69, 0x6f, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x0f, 0x64,
+       0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x6f, 
0x73, 0x74, 0x12, 0x28,
+       0x0a, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 
0x6e, 0x50, 0x6f, 0x72,
+       0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x64, 0x65, 0x73, 
0x74, 0x69, 0x6e, 0x61,
+       0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 
0x73, 0x6f, 0x75, 0x72,
+       0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x0a, 0x73, 0x6f,
+       0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x79, 0x0a, 0x17, 
0x43, 0x6f, 0x6d, 0x6d,
+       0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 
0x52, 0x65, 0x71, 0x75,
+       0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
+       0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 
0x65, 0x63, 0x75, 0x74,
+       0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x72, 0x67, 
0x75, 0x6d, 0x65, 0x6e,
+       0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x72, 
0x67, 0x75, 0x6d, 0x65,
+       0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x69, 
0x6e, 0x67, 0x44, 0x69,
+       0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 
0x6b, 0x69, 0x6e, 0x67,
+       0x44, 0x69, 0x72, 0x22, 0x8b, 0x01, 0x0a, 0x17, 0x4a, 0x75, 0x70, 0x79, 
0x74, 0x65, 0x72, 0x45,
        0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x12,
        0x20, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 
0x49, 0x64, 0x18, 0x01,
        0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 
0x69, 0x6f, 0x6e, 0x49,
-       0x64, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 
0x65, 0x72, 0x4e, 0x61,
-       0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 
0x6e, 0x74, 0x61, 0x69,
-       0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 
0x72, 0x67, 0x75, 0x6d,
-       0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 
0x61, 0x72, 0x67, 0x75,
-       0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x6f, 0x75, 
0x6e, 0x74, 0x50, 0x61,
-       0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 
0x75, 0x6e, 0x74, 0x50,
-       0x61, 0x74, 0x68, 0x22, 0xe9, 0x01, 0x0a, 0x15, 0x54, 0x75, 0x6e, 0x6e, 
0x65, 0x6c, 0x43, 0x72,
-       0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 
0x74, 0x12, 0x28, 0x0a,
-       0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 
0x48, 0x6f, 0x73, 0x74,
-       0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 
0x69, 0x6e, 0x61, 0x74,
-       0x69, 0x6f, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 
0x65, 0x73, 0x74, 0x69,
-       0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x02, 
0x20, 0x01, 0x28, 0x09,
-       0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 
0x6e, 0x50, 0x6f, 0x72,
-       0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x73, 0x68, 0x55, 0x73, 0x65, 0x72, 
0x4e, 0x61, 0x6d, 0x65,
-       0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x73, 0x68, 0x55, 
0x73, 0x65, 0x72, 0x4e,
-       0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 
0x65, 0x50, 0x6f, 0x72,
-       0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 
0x72, 0x63, 0x65, 0x50,
-       0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x73, 0x68, 0x4b, 0x65, 
0x79, 0x50, 0x61, 0x74,
-       0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x73, 0x68, 
0x4b, 0x65, 0x79, 0x50,
-       0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 
0x6f, 0x72, 0x64, 0x18,
-       0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 
0x6f, 0x72, 0x64, 0x22,
-       0x8e, 0x01, 0x0a, 0x18, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x65, 
0x72, 0x6d, 0x69, 0x6e,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 
0x12, 0x28, 0x0a, 0x0f,
-       0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 
0x6f, 0x73, 0x74, 0x18,
-       0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 
0x6e, 0x61, 0x74, 0x69,
-       0x6f, 0x6e, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x65, 
0x73, 0x74, 0x69, 0x6e,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 
0x01, 0x28, 0x05, 0x52,
-       0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 
0x50, 0x6f, 0x72, 0x74,
-       0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 
0x72, 0x74, 0x18, 0x03,
-       0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 
0x50, 0x6f, 0x72, 0x74,
-       0x22, 0x79, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 
0x78, 0x65, 0x63, 0x75,
-       0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 
0x20, 0x0a, 0x0b, 0x65,
-       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 
0x20, 0x01, 0x28, 0x09,
-       0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 
0x64, 0x12, 0x1c, 0x0a,
-       0x09, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 
0x20, 0x03, 0x28, 0x09,
-       0x52, 0x09, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 
0x1e, 0x0a, 0x0a, 0x77,
-       0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x18, 0x03, 0x20, 
0x01, 0x28, 0x09, 0x52,
-       0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x22, 
0x3d, 0x0a, 0x19, 0x54,
-       0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 
0x75, 0x74, 0x69, 0x6f,
-       0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 
0x65, 0x78, 0x65, 0x63,
-       0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x0b, 0x65,
-       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x2a, 
0x0a, 0x10, 0x4b, 0x69,
-       0x6c, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x12, 0x16,
-       0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x06,
-       0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xbb, 0x04, 0x0a, 0x0d, 0x53, 
0x65, 0x72, 0x76, 0x65,
-       0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x74, 0x0a, 0x19, 
0x63, 0x6f, 0x6e, 0x74,
-       0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 
0x6f, 0x6e, 0x52, 0x65,
-       0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x34, 0x2e, 0x6f, 0x72,
-       0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 
0x61, 0x76, 0x61, 0x74,
-       0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 
0x61, 0x69, 0x6e, 0x65,
-       0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x71, 0x75, 0x65, 0x73,
-       0x74, 0x48, 0x00, 0x52, 0x19, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 
0x65, 0x72, 0x45, 0x78,
-       0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x12, 0x6e,
-       0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 
0x63, 0x75, 0x74, 0x69,
-       0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 
0x01, 0x28, 0x0b, 0x32,
-       0x32, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 
0x2e, 0x61, 0x69, 0x72,
-       0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 
0x43, 0x6f, 0x6d, 0x6d,
-       0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 
0x52, 0x65, 0x71, 0x75,
-       0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 
0x6e, 0x64, 0x45, 0x78,
-       0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x12, 0x74,
-       0x0a, 0x19, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 
0x78, 0x65, 0x63, 0x75,
-       0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 
0x03, 0x20, 0x01, 0x28,
+       0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 
0x49, 0x64, 0x18, 0x02,
+       0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 
0x6e, 0x49, 0x64, 0x12,
+       0x1c, 0x0a, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 
0x18, 0x03, 0x20, 0x01,
+       0x28, 0x08, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 
0x65, 0x12, 0x12, 0x0a,
+       0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x04, 0x63, 0x6f, 0x64,
+       0x65, 0x22, 0x3d, 0x0a, 0x19, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 
0x74, 0x65, 0x45, 0x78,
+       0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x12, 0x20,
+       0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 
0x64, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 
0x6f, 0x6e, 0x49, 0x64,
+       0x22, 0x2a, 0x0a, 0x10, 0x4b, 0x69, 0x6c, 0x6c, 0x41, 0x67, 0x65, 0x6e, 
0x74, 0x52, 0x65, 0x71,
+       0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 
0x6f, 0x6e, 0x18, 0x01,
+       0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 
0x22, 0xab, 0x05, 0x0a,
+       0x0d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 
0x67, 0x65, 0x12, 0x74,
+       0x0a, 0x19, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 
0x78, 0x65, 0x63, 0x75,
+       0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 
0x01, 0x20, 0x01, 0x28,
        0x0b, 0x32, 0x34, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2e, 0x61,
-       0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 
0x74, 0x2e, 0x54, 0x65,
-       0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
-       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x19, 0x74, 
0x65, 0x72, 0x6d, 0x69,
-       0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 
0x6e, 0x52, 0x65, 0x71,
-       0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x10, 0x6b, 0x69, 0x6c, 0x6c, 
0x41, 0x67, 0x65, 0x6e,
-       0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 
0x28, 0x0b, 0x32, 0x2b,
-       0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 
0x61, 0x69, 0x72, 0x61,
-       0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4b, 
0x69, 0x6c, 0x6c, 0x41,
-       0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 
0x00, 0x52, 0x10, 0x6b,
-       0x69, 0x6c, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x12,
-       0x68, 0x0a, 0x15, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x72, 0x65, 
0x61, 0x74, 0x69, 0x6f,
-       0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 
0x28, 0x0b, 0x32, 0x30,
-       0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 
0x61, 0x69, 0x72, 0x61,
-       0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x54, 
0x75, 0x6e, 0x6e, 0x65,
-       0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 
0x75, 0x65, 0x73, 0x74,
-       0x48, 0x00, 0x52, 0x15, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x72, 
0x65, 0x61, 0x74, 0x69,
-       0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x09, 0x0a, 
0x07, 0x6d, 0x65, 0x73,
-       0x73, 0x61, 0x67, 0x65, 0x32, 0x86, 0x01, 0x0a, 0x19, 0x41, 0x67, 0x65, 
0x6e, 0x74, 0x43, 0x6f,
-       0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 
0x65, 0x72, 0x76, 0x69,
-       0x63, 0x65, 0x12, 0x69, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 
0x4d, 0x65, 0x73, 0x73,
-       0x61, 0x67, 0x65, 0x42, 0x75, 0x73, 0x12, 0x27, 0x2e, 0x6f, 0x72, 0x67, 
0x2e, 0x61, 0x70, 0x61,
-       0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 
0x2e, 0x61, 0x67, 0x65,
-       0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 
0x61, 0x67, 0x65, 0x1a,
-       0x28, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 
0x2e, 0x61, 0x69, 0x72,
-       0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 
0x53, 0x65, 0x72, 0x76,
-       0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 
0x01, 0x42, 0x3f, 0x0a,
-       0x19, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 
0x61, 0x69, 0x72, 0x61,
-       0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x42, 0x17, 
0x41, 0x67, 0x65, 0x6e,
-       0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x50, 0x72,
-       0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x07, 0x70, 0x72, 0x6f, 0x74, 0x6f, 
0x73, 0x2f, 0x62, 0x06,
-       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+       0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 
0x74, 0x2e, 0x43, 0x6f,
+       0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 
0x74, 0x69, 0x6f, 0x6e,
+       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x19, 0x63, 
0x6f, 0x6e, 0x74, 0x61,
+       0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 
0x6e, 0x52, 0x65, 0x71,
+       0x75, 0x65, 0x73, 0x74, 0x12, 0x6e, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 
0x61, 0x6e, 0x64, 0x45,
+       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x18,
+       0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 
0x61, 0x70, 0x61, 0x63,
+       0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 
0x61, 0x67, 0x65, 0x6e,
+       0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 
0x63, 0x75, 0x74, 0x69,
+       0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 
0x17, 0x63, 0x6f, 0x6d,
+       0x6d, 0x61, 0x6e, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 
0x6e, 0x52, 0x65, 0x71,
+       0x75, 0x65, 0x73, 0x74, 0x12, 0x74, 0x0a, 0x19, 0x74, 0x65, 0x72, 0x6d, 
0x69, 0x6e, 0x61, 0x74,
+       0x65, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 
0x71, 0x75, 0x65, 0x73,
+       0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6f, 0x72, 
0x67, 0x2e, 0x61, 0x70,
+       0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 
0x61, 0x2e, 0x61, 0x67,
+       0x65, 0x6e, 0x74, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 
0x65, 0x45, 0x78, 0x65,
+       0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 
0x74, 0x48, 0x00, 0x52,
+       0x19, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x45, 0x78, 
0x65, 0x63, 0x75, 0x74,
+       0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 
0x0a, 0x10, 0x6b, 0x69,
+       0x6c, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x18, 0x04,
+       0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 
0x70, 0x61, 0x63, 0x68,
+       0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 
0x67, 0x65, 0x6e, 0x74,
+       0x2e, 0x4b, 0x69, 0x6c, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 
0x71, 0x75, 0x65, 0x73,
+       0x74, 0x48, 0x00, 0x52, 0x10, 0x6b, 0x69, 0x6c, 0x6c, 0x41, 0x67, 0x65, 
0x6e, 0x74, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x15, 0x74, 0x75, 0x6e, 
0x6e, 0x65, 0x6c, 0x43,
+       0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 
0x73, 0x74, 0x18, 0x05,
+       0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 
0x70, 0x61, 0x63, 0x68,
+       0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 
0x67, 0x65, 0x6e, 0x74,
+       0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 
0x69, 0x6f, 0x6e, 0x52,
+       0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x15, 0x74, 0x75, 
0x6e, 0x6e, 0x65, 0x6c,
+       0x43, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x12,
+       0x6e, 0x0a, 0x17, 0x6a, 0x75, 0x70, 0x79, 0x74, 0x65, 0x72, 0x45, 0x78, 
0x65, 0x63, 0x75, 0x74,
+       0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x06, 
0x20, 0x01, 0x28, 0x0b,
+       0x32, 0x32, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 
0x65, 0x2e, 0x61, 0x69,
+       0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 
0x2e, 0x4a, 0x75, 0x70,
+       0x79, 0x74, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 
0x6e, 0x52, 0x65, 0x71,
+       0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x6a, 0x75, 0x70, 0x79, 
0x74, 0x65, 0x72, 0x45,
+       0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x42,
+       0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x86, 
0x01, 0x0a, 0x19, 0x41,
+       0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 
0x61, 0x74, 0x69, 0x6f,
+       0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x10, 
0x63, 0x72, 0x65, 0x61,
+       0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x75, 0x73, 
0x12, 0x27, 0x2e, 0x6f,
+       0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x61, 0x69, 
0x72, 0x61, 0x76, 0x61,
+       0x74, 0x61, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x67, 0x65, 
0x6e, 0x74, 0x4d, 0x65,
+       0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x28, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 
0x61, 0x70, 0x61, 0x63,
+       0x68, 0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 
0x61, 0x67, 0x65, 0x6e,
+       0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 
0x61, 0x67, 0x65, 0x28,
+       0x01, 0x30, 0x01, 0x42, 0x3f, 0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x61, 
0x70, 0x61, 0x63, 0x68,
+       0x65, 0x2e, 0x61, 0x69, 0x72, 0x61, 0x76, 0x61, 0x74, 0x61, 0x2e, 0x61, 
0x67, 0x65, 0x6e, 0x74,
+       0x42, 0x17, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 
0x6e, 0x69, 0x63, 0x61,
+       0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 
0x07, 0x70, 0x72, 0x6f,
+       0x74, 0x6f, 0x73, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1110,40 +1303,44 @@ func file_agent_communication_proto_rawDescGZIP() 
[]byte {
        return file_agent_communication_proto_rawDescData
 }
 
-var file_agent_communication_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
+var file_agent_communication_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
 var file_agent_communication_proto_goTypes = []any{
        (*AgentPing)(nil),                  // 0: 
org.apache.airavata.agent.AgentPing
        (*CommandExecutionResponse)(nil),   // 1: 
org.apache.airavata.agent.CommandExecutionResponse
        (*ContainerExecutionResponse)(nil), // 2: 
org.apache.airavata.agent.ContainerExecutionResponse
-       (*TerminateExecutionResponse)(nil), // 3: 
org.apache.airavata.agent.TerminateExecutionResponse
-       (*TunnelCreationResponse)(nil),     // 4: 
org.apache.airavata.agent.TunnelCreationResponse
-       (*TunnelTerminationResponse)(nil),  // 5: 
org.apache.airavata.agent.TunnelTerminationResponse
-       (*AgentMessage)(nil),               // 6: 
org.apache.airavata.agent.AgentMessage
-       (*ContainerExecutionRequest)(nil),  // 7: 
org.apache.airavata.agent.ContainerExecutionRequest
-       (*TunnelCreationRequest)(nil),      // 8: 
org.apache.airavata.agent.TunnelCreationRequest
-       (*TunnelTerminationRequest)(nil),   // 9: 
org.apache.airavata.agent.TunnelTerminationRequest
-       (*CommandExecutionRequest)(nil),    // 10: 
org.apache.airavata.agent.CommandExecutionRequest
-       (*TerminateExecutionRequest)(nil),  // 11: 
org.apache.airavata.agent.TerminateExecutionRequest
-       (*KillAgentRequest)(nil),           // 12: 
org.apache.airavata.agent.KillAgentRequest
-       (*ServerMessage)(nil),              // 13: 
org.apache.airavata.agent.ServerMessage
+       (*JupyterExecutionResponse)(nil),   // 3: 
org.apache.airavata.agent.JupyterExecutionResponse
+       (*TerminateExecutionResponse)(nil), // 4: 
org.apache.airavata.agent.TerminateExecutionResponse
+       (*TunnelCreationResponse)(nil),     // 5: 
org.apache.airavata.agent.TunnelCreationResponse
+       (*TunnelTerminationResponse)(nil),  // 6: 
org.apache.airavata.agent.TunnelTerminationResponse
+       (*AgentMessage)(nil),               // 7: 
org.apache.airavata.agent.AgentMessage
+       (*ContainerExecutionRequest)(nil),  // 8: 
org.apache.airavata.agent.ContainerExecutionRequest
+       (*TunnelCreationRequest)(nil),      // 9: 
org.apache.airavata.agent.TunnelCreationRequest
+       (*TunnelTerminationRequest)(nil),   // 10: 
org.apache.airavata.agent.TunnelTerminationRequest
+       (*CommandExecutionRequest)(nil),    // 11: 
org.apache.airavata.agent.CommandExecutionRequest
+       (*JupyterExecutionRequest)(nil),    // 12: 
org.apache.airavata.agent.JupyterExecutionRequest
+       (*TerminateExecutionRequest)(nil),  // 13: 
org.apache.airavata.agent.TerminateExecutionRequest
+       (*KillAgentRequest)(nil),           // 14: 
org.apache.airavata.agent.KillAgentRequest
+       (*ServerMessage)(nil),              // 15: 
org.apache.airavata.agent.ServerMessage
 }
 var file_agent_communication_proto_depIdxs = []int32{
        0,  // 0: org.apache.airavata.agent.AgentMessage.agentPing:type_name -> 
org.apache.airavata.agent.AgentPing
        1,  // 1: 
org.apache.airavata.agent.AgentMessage.commandExecutionResponse:type_name -> 
org.apache.airavata.agent.CommandExecutionResponse
        2,  // 2: 
org.apache.airavata.agent.AgentMessage.containerExecutionResponse:type_name -> 
org.apache.airavata.agent.ContainerExecutionResponse
-       3,  // 3: 
org.apache.airavata.agent.AgentMessage.terminateExecutionResponse:type_name -> 
org.apache.airavata.agent.TerminateExecutionResponse
-       7,  // 4: 
org.apache.airavata.agent.ServerMessage.containerExecutionRequest:type_name -> 
org.apache.airavata.agent.ContainerExecutionRequest
-       10, // 5: 
org.apache.airavata.agent.ServerMessage.commandExecutionRequest:type_name -> 
org.apache.airavata.agent.CommandExecutionRequest
-       11, // 6: 
org.apache.airavata.agent.ServerMessage.terminateExecutionRequest:type_name -> 
org.apache.airavata.agent.TerminateExecutionRequest
-       12, // 7: 
org.apache.airavata.agent.ServerMessage.killAgentRequest:type_name -> 
org.apache.airavata.agent.KillAgentRequest
-       8,  // 8: 
org.apache.airavata.agent.ServerMessage.tunnelCreationRequest:type_name -> 
org.apache.airavata.agent.TunnelCreationRequest
-       6,  // 9: 
org.apache.airavata.agent.AgentCommunicationService.createMessageBus:input_type 
-> org.apache.airavata.agent.AgentMessage
-       13, // 10: 
org.apache.airavata.agent.AgentCommunicationService.createMessageBus:output_type
 -> org.apache.airavata.agent.ServerMessage
-       10, // [10:11] is the sub-list for method output_type
-       9,  // [9:10] is the sub-list for method input_type
-       9,  // [9:9] is the sub-list for extension type_name
-       9,  // [9:9] is the sub-list for extension extendee
-       0,  // [0:9] is the sub-list for field type_name
+       4,  // 3: 
org.apache.airavata.agent.AgentMessage.terminateExecutionResponse:type_name -> 
org.apache.airavata.agent.TerminateExecutionResponse
+       3,  // 4: 
org.apache.airavata.agent.AgentMessage.jupyterExecutionResponse:type_name -> 
org.apache.airavata.agent.JupyterExecutionResponse
+       8,  // 5: 
org.apache.airavata.agent.ServerMessage.containerExecutionRequest:type_name -> 
org.apache.airavata.agent.ContainerExecutionRequest
+       11, // 6: 
org.apache.airavata.agent.ServerMessage.commandExecutionRequest:type_name -> 
org.apache.airavata.agent.CommandExecutionRequest
+       13, // 7: 
org.apache.airavata.agent.ServerMessage.terminateExecutionRequest:type_name -> 
org.apache.airavata.agent.TerminateExecutionRequest
+       14, // 8: 
org.apache.airavata.agent.ServerMessage.killAgentRequest:type_name -> 
org.apache.airavata.agent.KillAgentRequest
+       9,  // 9: 
org.apache.airavata.agent.ServerMessage.tunnelCreationRequest:type_name -> 
org.apache.airavata.agent.TunnelCreationRequest
+       12, // 10: 
org.apache.airavata.agent.ServerMessage.jupyterExecutionRequest:type_name -> 
org.apache.airavata.agent.JupyterExecutionRequest
+       7,  // 11: 
org.apache.airavata.agent.AgentCommunicationService.createMessageBus:input_type 
-> org.apache.airavata.agent.AgentMessage
+       15, // 12: 
org.apache.airavata.agent.AgentCommunicationService.createMessageBus:output_type
 -> org.apache.airavata.agent.ServerMessage
+       12, // [12:13] is the sub-list for method output_type
+       11, // [11:12] is the sub-list for method input_type
+       11, // [11:11] is the sub-list for extension type_name
+       11, // [11:11] is the sub-list for extension extendee
+       0,  // [0:11] is the sub-list for field type_name
 }
 
 func init() { file_agent_communication_proto_init() }
@@ -1189,7 +1386,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[3].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TerminateExecutionResponse); i {
+                       switch v := v.(*JupyterExecutionResponse); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1201,7 +1398,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[4].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TunnelCreationResponse); i {
+                       switch v := v.(*TerminateExecutionResponse); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1213,7 +1410,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[5].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TunnelTerminationResponse); i {
+                       switch v := v.(*TunnelCreationResponse); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1225,7 +1422,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[6].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*AgentMessage); i {
+                       switch v := v.(*TunnelTerminationResponse); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1237,7 +1434,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[7].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*ContainerExecutionRequest); i {
+                       switch v := v.(*AgentMessage); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1249,7 +1446,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[8].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TunnelCreationRequest); i {
+                       switch v := v.(*ContainerExecutionRequest); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1261,7 +1458,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[9].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TunnelTerminationRequest); i {
+                       switch v := v.(*TunnelCreationRequest); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1273,7 +1470,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[10].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*CommandExecutionRequest); i {
+                       switch v := v.(*TunnelTerminationRequest); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1285,7 +1482,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[11].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*TerminateExecutionRequest); i {
+                       switch v := v.(*CommandExecutionRequest); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1297,7 +1494,7 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[12].Exporter = func(v 
any, i int) any {
-                       switch v := v.(*KillAgentRequest); i {
+                       switch v := v.(*JupyterExecutionRequest); i {
                        case 0:
                                return &v.state
                        case 1:
@@ -1309,6 +1506,30 @@ func file_agent_communication_proto_init() {
                        }
                }
                file_agent_communication_proto_msgTypes[13].Exporter = func(v 
any, i int) any {
+                       switch v := v.(*TerminateExecutionRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_agent_communication_proto_msgTypes[14].Exporter = func(v 
any, i int) any {
+                       switch v := v.(*KillAgentRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_agent_communication_proto_msgTypes[15].Exporter = func(v 
any, i int) any {
                        switch v := v.(*ServerMessage); i {
                        case 0:
                                return &v.state
@@ -1321,18 +1542,20 @@ func file_agent_communication_proto_init() {
                        }
                }
        }
-       file_agent_communication_proto_msgTypes[6].OneofWrappers = []any{
+       file_agent_communication_proto_msgTypes[7].OneofWrappers = []any{
                (*AgentMessage_AgentPing)(nil),
                (*AgentMessage_CommandExecutionResponse)(nil),
                (*AgentMessage_ContainerExecutionResponse)(nil),
                (*AgentMessage_TerminateExecutionResponse)(nil),
+               (*AgentMessage_JupyterExecutionResponse)(nil),
        }
-       file_agent_communication_proto_msgTypes[13].OneofWrappers = []any{
+       file_agent_communication_proto_msgTypes[15].OneofWrappers = []any{
                (*ServerMessage_ContainerExecutionRequest)(nil),
                (*ServerMessage_CommandExecutionRequest)(nil),
                (*ServerMessage_TerminateExecutionRequest)(nil),
                (*ServerMessage_KillAgentRequest)(nil),
                (*ServerMessage_TunnelCreationRequest)(nil),
+               (*ServerMessage_JupyterExecutionRequest)(nil),
        }
        type x struct{}
        out := protoimpl.TypeBuilder{
@@ -1340,7 +1563,7 @@ func file_agent_communication_proto_init() {
                        GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
                        RawDescriptor: file_agent_communication_proto_rawDesc,
                        NumEnums:      0,
-                       NumMessages:   14,
+                       NumMessages:   16,
                        NumExtensions: 0,
                        NumServices:   1,
                },
diff --git 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/controllers/AgentController.java
 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/controllers/AgentController.java
index afb458c5fb..19a35fe0e6 100644
--- 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/controllers/AgentController.java
+++ 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/controllers/AgentController.java
@@ -31,7 +31,8 @@ public class AgentController {
     public ResponseEntity<AgentTunnelAck> runTunnelCreationOnAgent(@Valid 
@RequestBody AgentTunnelCreationRequest tunnelRequest) {
         return 
ResponseEntity.accepted().body(agentHandler.runTunnelOnAgent(tunnelRequest));
     }
-    @PostMapping("/execute")
+
+    @PostMapping("/executecommandrequest")
     public ResponseEntity<AgentCommandAck> runCommandOnAgent(@Valid 
@RequestBody AgentCommandRequest commandRequest) {
         logger.info("Received command request to run on agent {}", 
commandRequest.getAgentId());
         if (agentHandler.isAgentUp(commandRequest.getAgentId()).isAgentUp()) {
@@ -44,9 +45,27 @@ public class AgentController {
         }
     }
 
-    @GetMapping("/execution/{executionId}")
+    @GetMapping("/executecommandresponse/{executionId}")
     public ResponseEntity<AgentCommandResponse> 
getExecutionResponse(@PathVariable("executionId") String executionId) {
         return 
ResponseEntity.accepted().body(agentHandler.getAgentCommandResponse(executionId));
     }
 
+    @PostMapping("/executejupyterrequest")
+    public ResponseEntity<JupyterExecutionAck> runJupyterOnAgent(@Valid 
@RequestBody JupyterExecutionRequest executionRequest) {
+        logger.info("Received jupyter execution request to run on agent {}", 
executionRequest.getAgentId());
+        if (agentHandler.isAgentUp(executionRequest.getAgentId()).isAgentUp()) 
{
+            return 
ResponseEntity.accepted().body(agentHandler.runJupyterOnAgent(executionRequest));
+        } else {
+            logger.warn("No agent is available to run on agent {}", 
executionRequest.getAgentId());
+            JupyterExecutionAck ack = new JupyterExecutionAck();
+            ack.setError("Agent not found");
+            return ResponseEntity.accepted().body(ack);
+        }
+    }
+
+    @GetMapping("/executejupyterresponse/{executionId}")
+    public ResponseEntity<JupyterExecutionResponse> 
getJupyterResponse(@PathVariable("executionId") String executionId) {
+        return 
ResponseEntity.accepted().body(agentHandler.getJupyterExecutionResponse(executionId));
+    }
+
 }
diff --git 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/handlers/AgentHandler.java
 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/handlers/AgentHandler.java
index 95cc86e2a3..a4b2ed02f2 100644
--- 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/handlers/AgentHandler.java
+++ 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/handlers/AgentHandler.java
@@ -3,7 +3,9 @@ package org.apache.airavata.agent.connection.service.handlers;
 import io.grpc.stub.StreamObserver;
 import net.devh.boot.grpc.server.service.GrpcService;
 import org.apache.airavata.agent.*;
+import org.apache.airavata.agent.JupyterExecutionResponse;
 import org.apache.airavata.agent.connection.service.models.*;
+import 
org.apache.airavata.agent.connection.service.models.JupyterExecutionRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -24,7 +26,8 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
     // <agentId, streamId>
     private final Map<String, String> AGENT_STREAM_MAPPING = new 
ConcurrentHashMap<>();
 
-    private final Map<String, CommandExecutionResponse> 
EXECUTION_RESPONSE_CACHE = new ConcurrentHashMap<>();
+    private final Map<String, CommandExecutionResponse> 
COMMAND_EXECUTION_RESPONSE_CACHE = new ConcurrentHashMap<>();
+    private final Map<String, JupyterExecutionResponse> 
JUPYTER_EXECUTION_RESPONSE_CACHE = new ConcurrentHashMap<>();
 
     public AgentInfoResponse isAgentUp(String agentId) {
 
@@ -38,16 +41,30 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
 
     public AgentCommandResponse getAgentCommandResponse(String executionId) {
         AgentCommandResponse agentCommandResponse = new AgentCommandResponse();
-        if (EXECUTION_RESPONSE_CACHE.containsKey(executionId)) {
-            
agentCommandResponse.setResponseString(EXECUTION_RESPONSE_CACHE.get(executionId).getResponseString());
+        if (COMMAND_EXECUTION_RESPONSE_CACHE.containsKey(executionId)) {
+            
agentCommandResponse.setResponseString(COMMAND_EXECUTION_RESPONSE_CACHE.get(executionId).getResponseString());
             agentCommandResponse.setExecutionId(executionId);
             agentCommandResponse.setAvailable(true);
+            COMMAND_EXECUTION_RESPONSE_CACHE.remove(executionId);
         } else {
             agentCommandResponse.setAvailable(false);
         }
         return agentCommandResponse;
     }
 
+    public 
org.apache.airavata.agent.connection.service.models.JupyterExecutionResponse 
getJupyterExecutionResponse(String executionId) {
+        
org.apache.airavata.agent.connection.service.models.JupyterExecutionResponse 
executionResponse = new 
org.apache.airavata.agent.connection.service.models.JupyterExecutionResponse();
+        if (JUPYTER_EXECUTION_RESPONSE_CACHE.containsKey(executionId)) {
+            
executionResponse.setResponseString(JUPYTER_EXECUTION_RESPONSE_CACHE.get(executionId).getResponseString());
+            executionResponse.setExecutionId(executionId);
+            executionResponse.setAvailable(true);
+            JUPYTER_EXECUTION_RESPONSE_CACHE.remove(executionId);
+        } else {
+            executionResponse.setAvailable(false);
+        }
+        return executionResponse;
+    }
+
     public AgentTunnelAck runTunnelOnAgent(AgentTunnelCreationRequest 
tunnelRequest) {
         AgentTunnelAck ack = new AgentTunnelAck();
 
@@ -77,6 +94,38 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
 
         return ack;
     }
+
+    public JupyterExecutionAck runJupyterOnAgent(JupyterExecutionRequest 
jupyterExecutionRequest) {
+        String executionId = UUID.randomUUID().toString();
+        JupyterExecutionAck ack = new JupyterExecutionAck();
+        ack.setExecutionId(executionId);
+
+        if 
(AGENT_STREAM_MAPPING.containsKey(jupyterExecutionRequest.getAgentId()) &&
+                
ACTIVE_STREAMS.containsKey(AGENT_STREAM_MAPPING.get(jupyterExecutionRequest.getAgentId())))
 {
+            String streamId = 
AGENT_STREAM_MAPPING.get(jupyterExecutionRequest.getAgentId());
+            StreamObserver<ServerMessage> streamObserver = 
ACTIVE_STREAMS.get(streamId);
+
+            try {
+                logger.info("Running a jupyter on agent {}", 
jupyterExecutionRequest.getAgentId());
+                
streamObserver.onNext(ServerMessage.newBuilder().setJupyterExecutionRequest(
+                        
org.apache.airavata.agent.JupyterExecutionRequest.newBuilder().build().newBuilder()
+                                .setExecutionId(executionId)
+                                
.setSessionId(jupyterExecutionRequest.getSessionId())
+                                .setCode(jupyterExecutionRequest.getCode())
+                                
.setKeepAlive(jupyterExecutionRequest.isKeepAlive()).build()).build());
+
+            } catch (Exception e) {
+                logger.error("Failed to submit jupyter execution request {} on 
agent {}",
+                        executionId, jupyterExecutionRequest.getAgentId(), e);
+                ack.setError(e.getMessage());
+            }
+        } else {
+            logger.warn("No agent found to run jupyter execution on agent {}", 
jupyterExecutionRequest.getAgentId());
+            ack.setError("No agent found to run jupyter execution on agent " + 
jupyterExecutionRequest.getAgentId());
+        }
+        return ack;
+    }
+
     public AgentCommandAck runCommandOnAgent(AgentCommandRequest 
commandRequest) {
 
         String executionId = UUID.randomUUID().toString();
@@ -116,7 +165,7 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
 
     private void handleCommandExecutionResponse (CommandExecutionResponse 
commandExecutionResponse) {
         logger.info("Received command execution response for execution id {}", 
commandExecutionResponse.getExecutionId());
-        
EXECUTION_RESPONSE_CACHE.put(commandExecutionResponse.getExecutionId(), 
commandExecutionResponse);
+        
COMMAND_EXECUTION_RESPONSE_CACHE.put(commandExecutionResponse.getExecutionId(), 
commandExecutionResponse);
     }
 
     private void handleContainerExecutionResponse (ContainerExecutionResponse 
containerExecutionResponse) {
@@ -127,6 +176,11 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
 
     }
 
+    private void handleJupyterExecutionResponse (JupyterExecutionResponse 
executionResponse) {
+        logger.info("Received jupyter execution response for execution id {}", 
executionResponse.getExecutionId());
+        
JUPYTER_EXECUTION_RESPONSE_CACHE.put(executionResponse.getExecutionId(), 
executionResponse);
+    }
+
     private String generateStreamId() {
         // Generate a unique ID for each stream
         return java.util.UUID.randomUUID().toString();
@@ -154,6 +208,9 @@ public class AgentHandler extends 
AgentCommunicationServiceGrpc.AgentCommunicati
                     case TERMINATEEXECUTIONRESPONSE -> {
                         
handleAgentTerminationResponse(request.getTerminateExecutionResponse());
                     }
+                    case JUPYTEREXECUTIONRESPONSE -> {
+                        
handleJupyterExecutionResponse(request.getJupyterExecutionResponse());
+                    }
                 }
             }
 
diff --git 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionAck.java
 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionAck.java
new file mode 100644
index 0000000000..125adcc2bd
--- /dev/null
+++ 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionAck.java
@@ -0,0 +1,4 @@
+package org.apache.airavata.agent.connection.service.models;
+
+public class JupyterExecutionAck extends AgentCommandAck {
+}
diff --git 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionRequest.java
 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionRequest.java
new file mode 100644
index 0000000000..2fe60f7c06
--- /dev/null
+++ 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionRequest.java
@@ -0,0 +1,40 @@
+package org.apache.airavata.agent.connection.service.models;
+
+public class JupyterExecutionRequest {
+    private String sessionId;
+    private boolean keepAlive;
+    private String code;
+    private String agentId;
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public boolean isKeepAlive() {
+        return keepAlive;
+    }
+
+    public void setKeepAlive(boolean keepAlive) {
+        this.keepAlive = keepAlive;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getAgentId() {
+        return agentId;
+    }
+
+    public void setAgentId(String agentId) {
+        this.agentId = agentId;
+    }
+}
diff --git 
a/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionResponse.java
 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionResponse.java
new file mode 100644
index 0000000000..bd58c80ffa
--- /dev/null
+++ 
b/modules/agent-framework/connection-service/src/main/java/org/apache/airavata/agent/connection/service/models/JupyterExecutionResponse.java
@@ -0,0 +1,41 @@
+package org.apache.airavata.agent.connection.service.models;
+
+public class JupyterExecutionResponse {
+
+    private String executionId;
+    private String sessionId;
+    private String responseString;
+    private boolean isAvailable;
+
+    public String getExecutionId() {
+        return executionId;
+    }
+
+    public void setExecutionId(String executionId) {
+        this.executionId = executionId;
+    }
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public String getResponseString() {
+        return responseString;
+    }
+
+    public void setResponseString(String responseString) {
+        this.responseString = responseString;
+    }
+
+    public boolean isAvailable() {
+        return isAvailable;
+    }
+
+    public void setAvailable(boolean available) {
+        isAvailable = available;
+    }
+}
diff --git 
a/modules/agent-framework/connection-service/src/main/proto/agent-communication.proto
 
b/modules/agent-framework/connection-service/src/main/proto/agent-communication.proto
index 0e54285ebd..762471c700 100644
--- 
a/modules/agent-framework/connection-service/src/main/proto/agent-communication.proto
+++ 
b/modules/agent-framework/connection-service/src/main/proto/agent-communication.proto
@@ -25,6 +25,12 @@ message ContainerExecutionResponse {
   string responseString = 2;
 }
 
+message JupyterExecutionResponse {
+  string executionId = 1;
+  string sessionId = 2;
+  string responseString = 3;
+}
+
 message TerminateExecutionResponse {
   string status = 1;
   string description = 2;
@@ -44,6 +50,7 @@ message AgentMessage {
     CommandExecutionResponse commandExecutionResponse = 2;
     ContainerExecutionResponse containerExecutionResponse = 3;
     TerminateExecutionResponse terminateExecutionResponse = 4;
+    JupyterExecutionResponse jupyterExecutionResponse = 5;
   }
 }
 
@@ -75,6 +82,13 @@ message CommandExecutionRequest {
   string workingDir = 3;
 }
 
+message JupyterExecutionRequest {
+  string executionId = 1;
+  string sessionId = 2;
+  bool keepAlive = 3;
+  string code = 4;
+}
+
 message TerminateExecutionRequest {
   string executionId = 1;
 }
@@ -90,5 +104,6 @@ message ServerMessage {
     TerminateExecutionRequest terminateExecutionRequest = 3;
     KillAgentRequest killAgentRequest = 4;
     TunnelCreationRequest tunnelCreationRequest = 5;
+    JupyterExecutionRequest jupyterExecutionRequest = 6;
   }
 }
\ No newline at end of file

Reply via email to