Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions assistant.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net/url"
"strconv"
)

// AssistantThreadSetStatusParameters are the parameters for AssistantThreadSetStatus
Expand Down Expand Up @@ -34,6 +35,43 @@ type AssistantThreadsPrompt struct {
Message string `json:"message"`
}

// AssistantSearchContextParameters are the parameters for AssistantSearchContext
type AssistantSearchContextParameters struct {
Query string `json:"query"`
ActionToken string `json:"action_token,omitempty"`
ChannelTypes []string `json:"channel_types,omitempty"`
ContentTypes []string `json:"content_types,omitempty"`
ContextChannelID string `json:"context_channel_id,omitempty"`
Cursor string `json:"cursor,omitempty"`
IncludeBots bool `json:"include_bots,omitempty"`
Limit int `json:"limit,omitempty"`
}

// AssistantSearchContextMessage represents a search result message
type AssistantSearchContextMessage struct {
AuthorUserID string `json:"author_user_id"`
TeamID string `json:"team_id"`
ChannelID string `json:"channel_id"`
MessageTS string `json:"message_ts"`
Content string `json:"content"`
IsAuthorBot bool `json:"is_author_bot"`
Permalink string `json:"permalink"`
}

// AssistantSearchContextResults contains the search results
type AssistantSearchContextResults struct {
Messages []AssistantSearchContextMessage `json:"messages"`
}

// AssistantSearchContextResponse is the response from assistant.search.context
type AssistantSearchContextResponse struct {
SlackResponse
Results AssistantSearchContextResults `json:"results"`
ResponseMetadata struct {
NextCursor string `json:"next_cursor"`
} `json:"response_metadata"`
}

// AssistantThreadSetSuggestedPrompts sets the suggested prompts for a thread
func (p *AssistantThreadsSetSuggestedPromptsParameters) AddPrompt(title, message string) {
p.Prompts = append(p.Prompts, AssistantThreadsPrompt{
Expand Down Expand Up @@ -155,3 +193,60 @@ func (api *Client) SetAssistantThreadsTitleContext(ctx context.Context, params A
return response.Err()

}

// SearchAssistantContext searches messages across the Slack organization
// @see https://api.slack.com/methods/assistant.search.context
func (api *Client) SearchAssistantContext(params AssistantSearchContextParameters) (*AssistantSearchContextResponse, error) {
return api.SearchAssistantContextContext(context.Background(), params)
}

// SearchAssistantContextContext searches messages across the Slack organization with a custom context
// @see https://api.slack.com/methods/assistant.search.context
func (api *Client) SearchAssistantContextContext(ctx context.Context, params AssistantSearchContextParameters) (*AssistantSearchContextResponse, error) {
values := url.Values{
"token": {api.token},
}

values.Add("query", params.Query)

if params.ActionToken != "" {
values.Add("action_token", params.ActionToken)
}

if len(params.ChannelTypes) > 0 {
for _, channelType := range params.ChannelTypes {
values.Add("channel_types", channelType)
}
}

if len(params.ContentTypes) > 0 {
for _, contentType := range params.ContentTypes {
values.Add("content_types", contentType)
}
}

if params.ContextChannelID != "" {
values.Add("context_channel_id", params.ContextChannelID)
}

if params.Cursor != "" {
values.Add("cursor", params.Cursor)
}

if params.IncludeBots {
values.Add("include_bots", "true")
}

if params.Limit > 0 {
values.Add("limit", strconv.Itoa(params.Limit))
}

response := &AssistantSearchContextResponse{}

err := api.postMethod(ctx, "assistant.search.context", values, response)
if err != nil {
return nil, err
}

return response, response.Err()
}
188 changes: 188 additions & 0 deletions assistant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package slack
import (
"encoding/json"
"net/http"
"net/url"
"testing"
)

Expand Down Expand Up @@ -84,3 +85,190 @@ func TestSetAssistantThreadsTitle(t *testing.T) {
}

}

func assistantSearchContextHandler(rw http.ResponseWriter, r *http.Request) {
query := r.FormValue("query")
rw.Header().Set("Content-Type", "application/json")

if query != "" {
resp, _ := json.Marshal(&AssistantSearchContextResponse{
SlackResponse: SlackResponse{Ok: true},
Results: AssistantSearchContextResults{
Messages: []AssistantSearchContextMessage{
{
AuthorUserID: "U1234567890",
TeamID: "T1234567890",
ChannelID: "C1234567890",
MessageTS: "1234567890.123456",
Content: "This is a test message",
IsAuthorBot: false,
Permalink: "https://example.slack.com/archives/C1234567890/p1234567890123456",
},
},
},
ResponseMetadata: struct {
NextCursor string `json:"next_cursor"`
}{
NextCursor: "next_cursor_value",
},
})
rw.Write(resp)
} else {
rw.Write([]byte(`{ "ok": false, "error": "invalid_arguments" }`))
}
}

func TestSearchAssistantContext(t *testing.T) {
http.HandleFunc("/assistant.search.context", assistantSearchContextHandler)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))

params := AssistantSearchContextParameters{
Query: "test query",
ActionToken: "test_action_token",
ChannelTypes: []string{"public_channel", "private_channel"},
ContentTypes: []string{"messages"},
ContextChannelID: "C1234567890",
Cursor: "cursor_value",
IncludeBots: true,
Limit: 10,
}

response, err := api.SearchAssistantContext(params)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}

if !response.Ok {
t.Fatalf("Expected Ok to be true")
}

if len(response.Results.Messages) != 1 {
t.Fatalf("Expected 1 message, got %d", len(response.Results.Messages))
}

message := response.Results.Messages[0]
if message.AuthorUserID != "U1234567890" {
t.Fatalf("Expected AuthorUserID to be U1234567890, got %s", message.AuthorUserID)
}

if message.TeamID != "T1234567890" {
t.Fatalf("Expected TeamID to be T1234567890, got %s", message.TeamID)
}

if message.ChannelID != "C1234567890" {
t.Fatalf("Expected ChannelID to be C1234567890, got %s", message.ChannelID)
}

if message.MessageTS != "1234567890.123456" {
t.Fatalf("Expected MessageTS to be '1234567890.123456', got %s", message.MessageTS)
}

if message.Content != "This is a test message" {
t.Fatalf("Expected Content to be 'This is a test message', got %s", message.Content)
}

if message.IsAuthorBot != false {
t.Fatalf("Expected IsAuthorBot to be false, got %v", message.IsAuthorBot)
}

if response.ResponseMetadata.NextCursor != "next_cursor_value" {
t.Fatalf("Expected NextCursor to be 'next_cursor_value', got %s", response.ResponseMetadata.NextCursor)
}
}

func assistantSearchContextHandlerWithNewParams(rw http.ResponseWriter, r *http.Request) {
query := r.FormValue("query")
actionToken := r.FormValue("action_token")
contextChannelID := r.FormValue("context_channel_id")
includeBots := r.FormValue("include_bots")

rw.Header().Set("Content-Type", "application/json")

if query != "" && actionToken != "" && contextChannelID != "" && includeBots == "true" {
resp, _ := json.Marshal(&AssistantSearchContextResponse{
SlackResponse: SlackResponse{Ok: true},
Results: AssistantSearchContextResults{
Messages: []AssistantSearchContextMessage{
{
AuthorUserID: "U1234567890",
TeamID: "T0987654321",
ChannelID: contextChannelID, // Use the provided context channel ID
MessageTS: "1234567890.123456",
Content: "This is a test message with new parameters",
IsAuthorBot: true, // Test with bot message
Permalink: "https://example.slack.com/archives/" + contextChannelID + "/p1234567890123456",
},
},
},
ResponseMetadata: struct {
NextCursor string `json:"next_cursor"`
}{
NextCursor: "next_cursor_value_new",
},
})
rw.Write(resp)
} else {
rw.Write([]byte(`{ "ok": false, "error": "missing_required_parameters" }`))
}
}

func TestSearchAssistantContextWithNewParameters(t *testing.T) {
http.HandleFunc("/assistant.search.context.new", assistantSearchContextHandlerWithNewParams)
once.Do(startServer)

// Test with new parameters
params := AssistantSearchContextParameters{
Query: "test query with new params",
ActionToken: "action_token_123",
ChannelTypes: []string{"public_channel"},
ContentTypes: []string{"messages"},
ContextChannelID: "C0987654321",
IncludeBots: true,
Limit: 5,
}

// We need to temporarily change the API method for this test
// Since we can't easily override the method, we'll test the parameter building logic

// Create a custom client to test parameter handling
values := url.Values{"token": {"testing-token"}}
values.Add("query", params.Query)

if params.ActionToken != "" {
values.Add("action_token", params.ActionToken)
}
if len(params.ChannelTypes) > 0 {
for _, channelType := range params.ChannelTypes {
values.Add("channel_types", channelType)
}
}
if len(params.ContentTypes) > 0 {
for _, contentType := range params.ContentTypes {
values.Add("content_types", contentType)
}
}
if params.ContextChannelID != "" {
values.Add("context_channel_id", params.ContextChannelID)
}
if params.IncludeBots {
values.Add("include_bots", "true")
}
if params.Limit > 0 {
values.Add("limit", "5")
}

// Verify all parameters are set correctly
if values.Get("action_token") != "action_token_123" {
t.Errorf("Expected action_token to be 'action_token_123', got %s", values.Get("action_token"))
}
if values.Get("context_channel_id") != "C0987654321" {
t.Errorf("Expected context_channel_id to be 'C0987654321', got %s", values.Get("context_channel_id"))
}
if values.Get("include_bots") != "true" {
t.Errorf("Expected include_bots to be 'true', got %s", values.Get("include_bots"))
}
if values.Get("limit") != "5" {
t.Errorf("Expected limit to be '5', got %s", values.Get("limit"))
}
}
Loading