Skip to content

Commit

Permalink
feat: Slack AI & Assistants Compatibility (#1331)
Browse files Browse the repository at this point in the history
  • Loading branch information
MattDavisRV authored Nov 6, 2024
1 parent 203cdb2 commit 00d0e9a
Show file tree
Hide file tree
Showing 5 changed files with 414 additions and 77 deletions.
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 {
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 != "" {
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

0 comments on commit 00d0e9a

Please sign in to comment.