3333- Tool execution
3434- Conversation logic
3535
36+ Flow (mirrors the WebTalk/WebRTC flow):
37+ 1. Rapida sends ConversationInitialization — always the first message.
38+ Acknowledge it with initialization_response().
39+ 2. Rapida may send ConversationConfiguration to change stream mode.
40+ Acknowledge it with configuration_response().
41+ 3. Rapida sends ConversationUserMessage for each user turn.
42+ Reply with assistant_response() chunks.
43+
3644Usage:
3745 from rapida import AgentKitServer, AgentKitAgent
38-
46+
3947 class MyAgent(AgentKitAgent):
4048 def Talk(self, request_iterator, context):
4149 for request in request_iterator:
42- if request.HasField("configuration"):
50+ if request.HasField("initialization"):
51+ # Always first — acknowledge and set up your session
52+ yield self.initialization_response(request.initialization)
53+ elif request.HasField("configuration"):
4354 yield self.configuration_response(request.configuration)
4455 elif request.HasField("message"):
4556 msg = request.message
4657 # Your LLM logic here
4758 yield self.assistant_response(msg.id, "Hello!", completed=False)
4859 yield self.assistant_response(msg.id, "Hello!", completed=True)
49-
60+
5061 server = AgentKitServer(
5162 agent=MyAgent(),
5263 port=50051,
@@ -67,20 +78,21 @@ def Talk(self, request_iterator, context):
6778from grpc import ServerInterceptor
6879
6980from rapida .clients .protos .talk_api_pb2 import (
81+ ConversationInitialization ,
7082 ConversationConfiguration ,
7183 ConversationAssistantMessage ,
7284 ConversationDirective ,
7385 ConversationToolCall ,
7486 ConversationToolResult ,
7587)
76- from rapida .clients .protos .talk_api_pb2 import (
88+ from rapida .clients .protos .agentkit_pb2 import (
7789 TalkInput ,
7890 TalkOutput ,
7991)
8092from rapida .clients .protos .common_pb2 import (
8193 Error ,
8294)
83- from rapida .clients .protos .talk_api_pb2_grpc import (
95+ from rapida .clients .protos .agentkit_pb2_grpc import (
8496 AgentKitServicer ,
8597 add_AgentKitServicer_to_server ,
8698)
@@ -184,11 +196,20 @@ class AgentKitAgent(AgentKitServicer):
184196
185197 Subclass this and implement Talk() with your LLM logic.
186198
199+ The message flow mirrors WebTalk/WebRTC:
200+ 1. ConversationInitialization — always the first message. Acknowledge it.
201+ 2. ConversationConfiguration — optional mode change. Acknowledge it.
202+ 3. ConversationUserMessage — user turns. Reply with assistant_response().
203+
187204 Example:
188205 class MyAgent(AgentKitAgent):
189206 def Talk(self, request_iterator, context):
190207 for request in request_iterator:
191- if request.HasField("configuration"):
208+ if request.HasField("initialization"):
209+ # Always first — set up your session here
210+ conv_id = self.get_conversation_id(request)
211+ yield self.initialization_response(request.initialization)
212+ elif request.HasField("configuration"):
192213 yield self.configuration_response(request.configuration)
193214 elif request.HasField("message"):
194215 msg = request.message
@@ -218,19 +239,41 @@ def response(
218239 """
219240 return TalkOutput (code = code , success = success , ** kwargs )
220241
242+ def initialization_response (
243+ self , initialization : ConversationInitialization
244+ ) -> TalkOutput :
245+ """
246+ Acknowledge a ConversationInitialization from Rapida.
247+
248+ This should always be the first response yielded in Talk().
249+ Rapida always sends initialization as the first message on the stream,
250+ mirroring the WebTalk/WebRTC flow.
251+
252+ Args:
253+ initialization: The ConversationInitialization received from Rapida
254+
255+ Returns:
256+ TalkOutput acknowledging the initialization
257+ """
258+ return self .response (initialization = initialization )
259+
221260 def configuration_response (
222- self , configuration : ConversationConfiguration
261+ self , configuration : ConversationConfiguration = None
223262 ) -> TalkOutput :
224263 """
225264 Acknowledge a configuration request from Rapida.
226265
266+ Note: TalkOutput has no configuration field in its data oneof, so this
267+ sends a plain code-200 acknowledgement with no data payload.
268+ Configuration changes do not carry a data ack in the AgentKit protocol.
269+
227270 Args:
228- configuration: The configuration received from the request
271+ configuration: Unused; kept for API compatibility.
229272
230273 Returns:
231- TalkOutput acknowledging the configuration
274+ TalkOutput with code=200 and no data payload
232275 """
233- return self .response (configuration = configuration )
276+ return self .response ()
234277
235278 def assistant_response (
236279 self , msg_id : str , content : str , completed : bool = False
@@ -419,6 +462,38 @@ def get_message_id(self, request: TalkInput) -> Optional[str]:
419462 return request .message .id
420463 return None
421464
465+ def get_conversation_id (self , request : TalkInput ) -> Optional [int ]:
466+ """
467+ Extract the conversation ID from an initialization request.
468+
469+ Args:
470+ request: The incoming initialization request from Rapida
471+
472+ Returns:
473+ Conversation ID, or None if not an initialization request
474+ """
475+ if request .HasField ("initialization" ):
476+ return request .initialization .assistantConversationId
477+ return None
478+
479+ def get_assistant_id (self , request : TalkInput ) -> Optional [int ]:
480+ """
481+ Extract the assistant ID from an initialization request.
482+
483+ Args:
484+ request: The incoming initialization request from Rapida
485+
486+ Returns:
487+ Assistant ID, or None if not an initialization request or assistant is unset
488+ """
489+ if request .HasField ("initialization" ) and request .initialization .HasField ("assistant" ):
490+ return request .initialization .assistant .assistantId
491+ return None
492+
493+ def is_initialization_request (self , request : TalkInput ) -> bool :
494+ """Check if request is the initial ConversationInitialization message."""
495+ return request .HasField ("initialization" )
496+
422497 def is_configuration_request (self , request : TalkInput ) -> bool :
423498 """Check if request is a configuration request."""
424499 return request .HasField ("configuration" )
@@ -464,14 +539,17 @@ class AgentKitServer:
464539 class MyAgent(AgentKitAgent):
465540 def Talk(self, request_iterator, context):
466541 for request in request_iterator:
467- if self.is_configuration_request(request):
542+ if self.is_initialization_request(request):
543+ # Always first — set up your session here
544+ yield self.initialization_response(request.initialization)
545+ elif self.is_configuration_request(request):
468546 yield self.configuration_response(request.configuration)
469547 elif self.is_text_message(request):
470548 msg_id = self.get_message_id(request)
471549 text = self.get_user_text(request)
472550 # Your LLM logic here
473551 yield self.assistant_response(msg_id, "Hello!", completed=True)
474-
552+
475553 server = AgentKitServer(agent=MyAgent(), port=50051)
476554 server.start()
477555 server.wait_for_termination()
0 commit comments