From c4488615573bf2300214b25f80c93472bf9aff0a Mon Sep 17 00:00:00 2001 From: Ti Wang Date: Tue, 3 Feb 2026 13:31:49 -0800 Subject: [PATCH] support context using custom data api --- .../internal/api/handle_create_session.go | 22 ++++++++- webchat-proxy/internal/ccaas/ccaip.go | 49 +++++++++++++++++-- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/webchat-proxy/internal/api/handle_create_session.go b/webchat-proxy/internal/api/handle_create_session.go index 2c9c9cd6..6ee363c2 100644 --- a/webchat-proxy/internal/api/handle_create_session.go +++ b/webchat-proxy/internal/api/handle_create_session.go @@ -62,7 +62,6 @@ func (s *Server) HandleCreateSession(w http.ResponseWriter, r *http.Request) { chatReq := &ccaas.CreateChatRequest{ ExternalIdentifier: participantID, MenuID: menuID, - Context: req.Context, } chatSession, err := s.CCaaS.CreateChatSession(r.Context(), conversationID, chatReq) @@ -75,6 +74,27 @@ func (s *Server) HandleCreateSession(w http.ResponseWriter, r *http.Request) { // Register participant name for webhook relay s.CCaaS.RegisterParticipant(chatSession.ID, req.Participant) + // Send custom data if context is provided + if len(req.Context) > 0 { + customData := make(map[string]ccaas.CustomDataItem) + for key, value := range req.Context { + // Convert value to string representation + valueStr := fmt.Sprintf("%v", value) + customData[key] = ccaas.CustomDataItem{ + Label: key, + Value: valueStr, + } + } + + err = s.CCaaS.SendCustomData(r.Context(), conversationID, chatSession.ID, customData) + if err != nil { + log.Printf("[%s] Session: WARNING failed to send custom data: %v", conversationID, err) + // Continue even if custom data fails - this is not critical + } else { + log.Printf("[%s] Session: Custom data sent successfully (%d items)", conversationID, len(customData)) + } + } + // Create a local session which manages the bidi grpc stream _, err = s.SessionManager.CreateSession(conversationID, req.Participant, chatSession.ID, chatSession.EndUserID) if err != nil { diff --git a/webchat-proxy/internal/ccaas/ccaip.go b/webchat-proxy/internal/ccaas/ccaip.go index e34fc438..762c4dbf 100644 --- a/webchat-proxy/internal/ccaas/ccaip.go +++ b/webchat-proxy/internal/ccaas/ccaip.go @@ -284,9 +284,6 @@ func (c *CCAIPConnector) CreateChatSession(ctx context.Context, convID string, r "menu_id": menuID, "end_user_id": ccaipEndUserID, "lang": lang, - "context": map[string]interface{}{ - "value": req.Context, - }, }, } @@ -376,6 +373,45 @@ func (c *CCAIPConnector) SendMessage(ctx context.Context, convID, chatID string, return nil } +// SendCustomData sends custom data (key/value pairs) to the CCAIP platform. +// This should be called after CreateChatSession but before SendMessage. +func (c *CCAIPConnector) SendCustomData(ctx context.Context, convID, chatID string, customData map[string]CustomDataItem) error { + url := fmt.Sprintf("%s/chats/%s/custom_data", c.Config.APIBaseURL, chatID) + + ccaipReq := map[string]interface{}{ + "signed": false, + "data": customData, + } + + body, _ := json.Marshal(ccaipReq) + log.Printf("[%s] CCAIP → POST %s (sendCustomData): %d items", convID, url, len(customData)) + + hReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body)) + if err != nil { + return err + } + + hReq.Header.Set("Content-Type", "application/json") + hReq.Header.Set("Accept", "application/json") + hReq.Header.Set("Authorization", c.getAuthHeader()) + + resp, err := c.HTTPClient.Do(hReq) + if err != nil { + log.Printf("[%s] CCAIP ← POST %s: ERROR %v", convID, url, err) + return err + } + defer resp.Body.Close() + + respBody, _ := io.ReadAll(resp.Body) + log.Printf("[%s] CCAIP ← POST %s: Status=%d", convID, url, resp.StatusCode) + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("failed to send custom data: status=%d body=%s", resp.StatusCode, string(respBody)) + } + + return nil +} + func (c *CCAIPConnector) EndSession(ctx context.Context, convID, chatID string, req *EndSessionRequest) error { url := fmt.Sprintf("%s/chats/%s", c.Config.APIBaseURL, chatID) @@ -463,3 +499,10 @@ type MessageBlock struct { type EndSessionRequest struct { FinishedByUserID string `json:"finished_by_user_id"` } + +// CustomDataItem represents a single custom data item with label and value. +type CustomDataItem struct { + Label string `json:"label"` + Value string `json:"value"` +} +