Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Slack AI & Assistants Compatibility #1331

Merged
merged 13 commits into from
Nov 6, 2024
Merged
153 changes: 153 additions & 0 deletions assistant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package slack

import (
"context"
"encoding/json"
"net/url"
)

// AssistantThreadSetStatusParameters are the parameters for AssistantThreadSetStatus
type AssistantThreadsSetStatusParameters struct {
ChannelID string `json:"channel_id"`
Status string `json:"status"`
ThreadTS string `json:"thread_ts"`
}

// AssistantThreadSetTitleParameters are the parameters for AssistantThreadSetTitle
type AssistantThreadsSetTitleParameters struct {
ChannelID string `json:"channel_id"`
ThreadTS string `json:"thread_ts"`
Title string `json:"title"`
}

// AssistantThreadSetSuggestedPromptsParameters are the parameters for AssistantThreadSetSuggestedPrompts
type AssistantThreadsSetSuggestedPromptsParameters struct {
MattDavisRV marked this conversation as resolved.
Show resolved Hide resolved
Title string `json:"title"`
ChannelID string `json:"channel_id"`
ThreadTS string `json:"thread_ts"`
Prompts []AssistantThreadsPrompt `json:"prompts"`
}

// AssistantThreadPrompt is a suggested prompt for a thread
type AssistantThreadsPrompt struct {
Title string `json:"title"`
Message string `json:"message"`
}

// AssistantThreadSetSuggestedPrompts sets the suggested prompts for a thread
func (p *AssistantThreadsSetSuggestedPromptsParameters) AddPrompt(title, message string) {
p.Prompts = append(p.Prompts, AssistantThreadsPrompt{
Title: title,
Message: message,
})
}

// SetAssistantThreadsSugesstedPrompts sets the suggested prompts for a thread
// @see https://api.slack.com/methods/assistant.threads.setSuggestedPrompts
func (api *Client) SetAssistantThreadsSuggestedPrompts(params AssistantThreadsSetSuggestedPromptsParameters) (err error) {
return api.SetAssistantThreadsSuggestedPromptsContext(context.Background(), params)
}

// SetAssistantThreadSuggestedPromptsContext sets the suggested prompts for a thread with a custom context
// @see https://api.slack.com/methods/assistant.threads.setSuggestedPrompts
func (api *Client) SetAssistantThreadsSuggestedPromptsContext(ctx context.Context, params AssistantThreadsSetSuggestedPromptsParameters) (err error) {

values := url.Values{
"token": {api.token},
}

if params.ThreadTS != "" {
values.Add("thread_ts", params.ThreadTS)
}

// Send Prompts as JSON
prompts, err := json.Marshal(params.Prompts)
if err != nil {
return err
}

values.Add("prompts", string(prompts))

response := struct {
SlackResponse
}{}

err = api.postMethod(ctx, "assistant.threads.setSuggestedPrompts", values, &response)
if err != nil {
return
}

return response.Err()
}

// SetAssistantThreadStatus sets the status of a thread
// @see https://api.slack.com/methods/assistant.threads.setStatus
func (api *Client) SetAssistantThreadsStatus(params AssistantThreadsSetStatusParameters) (err error) {
return api.SetAssistantThreadsStatusContext(context.Background(), params)
}

// SetAssistantThreadStatusContext sets the status of a thread with a custom context
// @see https://api.slack.com/methods/assistant.threads.setStatus
func (api *Client) SetAssistantThreadsStatusContext(ctx context.Context, params AssistantThreadsSetStatusParameters) (err error) {

values := url.Values{
"token": {api.token},
}

if params.ThreadTS != "" {
values.Add("thread_ts", params.ThreadTS)
}

// Always send the status parameter, if empty, it will clear any existing status
values.Add("status", params.Status)

response := struct {
SlackResponse
}{}

err = api.postMethod(ctx, "assistant.threads.setStatus", values, &response)
if err != nil {
return
}

return response.Err()
}

// SetAssistantThreadsTitle sets the title of a thread
// @see https://api.slack.com/methods/assistant.threads.setTitle
func (api *Client) SetAssistantThreadsTitle(params AssistantThreadsSetTitleParameters) (err error) {
return api.SetAssistantThreadsTitleContext(context.Background(), params)
}

// SetAssistantThreadsTitleContext sets the title of a thread with a custom context
// @see https://api.slack.com/methods/assistant.threads.setTitle
func (api *Client) SetAssistantThreadsTitleContext(ctx context.Context, params AssistantThreadsSetTitleParameters) (err error) {

values := url.Values{
"token": {api.token},
}

if params.ChannelID != "" {
MattDavisRV marked this conversation as resolved.
Show resolved Hide resolved
values.Add("channel_id", params.ChannelID)
}

if params.ThreadTS != "" {
values.Add("thread_ts", params.ThreadTS)
}

if params.Title != "" {
values.Add("title", params.Title)
}

response := struct {
SlackResponse
}{}

err = api.postMethod(ctx, "assistant.threads.setTitle", values, &response)
if err != nil {
return
}

return response.Err()

}
86 changes: 86 additions & 0 deletions assistant_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package slack

import (
"encoding/json"
"net/http"
"testing"
)

func TestAssistantThreadsSuggestedPrompts(t *testing.T) {

http.HandleFunc("/assistant.threads.setSuggestedPrompts", okJSONHandler)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))

params := AssistantThreadsSetSuggestedPromptsParameters{
ChannelID: "CXXXXXXXX",
ThreadTS: "1234567890.123456",
}

params.AddPrompt("title1", "message1")
params.AddPrompt("title2", "message2")

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

}

func TestSetAssistantThreadsStatus(t *testing.T) {

http.HandleFunc("/assistant.threads.setStatus", okJSONHandler)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))

params := AssistantThreadsSetStatusParameters{
ChannelID: "CXXXXXXXX",
ThreadTS: "1234567890.123456",
Status: "updated status",
}

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

}

func assistantThreadsTitleHandler(rw http.ResponseWriter, r *http.Request) {

channelID := r.FormValue("channel_id")
threadTS := r.FormValue("thread_ts")
title := r.FormValue("title")

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

if channelID != "" && threadTS != "" && title != "" {

resp, _ := json.Marshal(&addBookmarkResponse{
SlackResponse: SlackResponse{Ok: true},
})
rw.Write(resp)
} else {
rw.Write([]byte(`{ "ok": false, "error": "errored" }`))
}

}

func TestSetAssistantThreadsTitle(t *testing.T) {

http.HandleFunc("/assistant.threads.setTitle", assistantThreadsTitleHandler)
once.Do(startServer)
api := New("testing-token", OptionAPIURL("http://"+serverAddr+"/"))

params := AssistantThreadsSetTitleParameters{
ChannelID: "CXXXXXXXX",
ThreadTS: "1234567890.123456",
Title: "updated title",
}

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

}
10 changes: 10 additions & 0 deletions block_section.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type SectionBlock struct {
BlockID string `json:"block_id,omitempty"`
Fields []*TextBlockObject `json:"fields,omitempty"`
Accessory *Accessory `json:"accessory,omitempty"`
Expand bool `json:"expand,omitempty"`
}

// BlockType returns the type of the block
Expand All @@ -25,6 +26,15 @@ func SectionBlockOptionBlockID(blockID string) SectionBlockOption {
}
}

// SectionBlockOptionExpand allows long text to be auto-expanded when displaying
//
// @see https://api.slack.com/reference/block-kit/blocks#section
func SectionBlockOptionExpand(shouldExpand bool) SectionBlockOption {
return func(block *SectionBlock) {
block.Expand = shouldExpand
}
}

// NewSectionBlock returns a new instance of a section block to be rendered
func NewSectionBlock(textObj *TextBlockObject, fields []*TextBlockObject, accessory *Accessory, options ...SectionBlockOption) *SectionBlock {
block := SectionBlock{
Expand Down
Loading