From 60b7a341a87e8176d9ac84fea861d0338af43c9b Mon Sep 17 00:00:00 2001 From: streamer45 Date: Mon, 27 May 2024 14:06:36 -0600 Subject: [PATCH 1/3] Implement conversation API endpoint --- go.mod | 43 ++++---- go.sum | 123 +++++++++------------- server/api.go | 2 + server/api_conversation.go | 118 +++++++++++++++++++++ server/api_test.go | 206 +++++++++++++++++++++++++++++++++++++ server/plugin.go | 2 +- 6 files changed, 400 insertions(+), 94 deletions(-) create mode 100644 server/api_conversation.go diff --git a/go.mod b/go.mod index 8a94f058..02d7562d 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-github/v41 v41.0.0 github.com/invopop/jsonschema v0.7.0 github.com/jmoiron/sqlx v1.3.5 - github.com/mattermost/mattermost/server/public v0.0.8 + github.com/mattermost/mattermost/server/public v0.1.4-0.20240525013543-51f42717b62e github.com/r3labs/sse/v2 v2.10.0 github.com/sashabaranov/go-openai v1.14.1 github.com/stretchr/testify v1.8.4 @@ -22,11 +22,11 @@ require ( github.com/blang/semver/v4 v4.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/validator/v10 v10.4.1 // indirect @@ -34,11 +34,12 @@ require ( github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/graph-gophers/graphql-go v1.5.1-0.20230110080634-edea822f558a // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-plugin v1.4.10 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -48,10 +49,10 @@ require ( github.com/leodido/go-urn v1.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect - github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect - github.com/mattermost/logr/v2 v2.0.18 // indirect + github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 // indirect + github.com/mattermost/logr/v2 v2.0.21 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -63,21 +64,21 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/tinylib/msgp v1.1.8 // indirect + github.com/stretchr/objx v0.5.1 // indirect + github.com/tinylib/msgp v1.1.9 // indirect github.com/trivago/tgo v1.0.7 // indirect github.com/ugorji/go/codec v1.1.7 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/wiggin77/merror v1.0.5 // indirect github.com/wiggin77/srslog v1.0.1 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.1 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/crypto v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/grpc v1.62.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 45dcbc0e..6bad64c9 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -34,8 +36,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a h1:etIrTD8BQqzColk9nKRusM9um5+1q0iOEJLqfBMIK64= github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a/go.mod h1:emQhSYTXqB0xxjLITTw4EaWZ+8IIQYw+kx9GqNUKdLg= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -48,13 +50,9 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -85,10 +83,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= @@ -99,21 +96,23 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v1.5.1-0.20230110080634-edea822f558a h1:i0+Se9S+2zL5CBxJouqn2Ej6UQMwH1c57ZB6DVnqck4= -github.com/graph-gophers/graphql-go v1.5.1-0.20230110080634-edea822f558a/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.4.10 h1:xUbmA4jC6Dq163/fWcp8P3JuHilrHHMLNRxzGQJ9hNk= -github.com/hashicorp/go-plugin v1.4.10/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= +github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= @@ -122,8 +121,8 @@ github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36 github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= -github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -153,12 +152,12 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8= github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34= -github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ0KNm4yZxxFvC1nvRz/gY/Daa35aI= -github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ= -github.com/mattermost/logr/v2 v2.0.18 h1:qiznuwwKckZJoGtBYc4Y9FAY97/oQwV1Pq9oO5qP5nk= -github.com/mattermost/logr/v2 v2.0.18/go.mod h1:1dm/YhTpozsqANXxo5Pi5zYLBsal2xY0pX+JZNbzYJY= -github.com/mattermost/mattermost/server/public v0.0.8 h1:YFgI5zT2U5xOvrYMb7s1YtwuLGNFModi8XJMS1zZHWE= -github.com/mattermost/mattermost/server/public v0.0.8/go.mod h1:sgXQrYzs+IJy51mB8E8OBljagk2u3YwQRoYlBH5goiw= +github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 h1:Y1Tu/swM31pVwwb2BTCsOdamENjjWCI6qmfHLbk6OZI= +github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956/go.mod h1:SRl30Lb7/QoYyohYeVBuqYvvmXSZJxZgiV3Zf6VbxjI= +github.com/mattermost/logr/v2 v2.0.21 h1:CMHsP+nrbRlEC4g7BwOk1GAnMtHkniFhlSQPXy52be4= +github.com/mattermost/logr/v2 v2.0.21/go.mod h1:kZkB/zqKL9e+RY5gB3vGpsyenC+TpuiOenjMkvJJbzc= +github.com/mattermost/mattermost/server/public v0.1.4-0.20240525013543-51f42717b62e h1:4LnLTPXgLQJsbQb7OcKRMbBahFsDM4IuyEqxUNFcPwE= +github.com/mattermost/mattermost/server/public v0.1.4-0.20240525013543-51f42717b62e/go.mod h1:PDPb/iqzJJ5ZvK/m70oDF55AXN/cOvVFj96Yu4e6j+Q= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -166,8 +165,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -186,7 +185,6 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -241,8 +239,9 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -252,11 +251,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU= +github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM= github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -264,18 +264,15 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/wiggin77/merror v1.0.5 h1:P+lzicsn4vPMycAf2mFf7Zk6G9eco5N+jB1qJ2XW3ME= github.com/wiggin77/merror v1.0.5/go.mod h1:H2ETSu7/bPE0Ymf4bEwdUoo73OOEkdClnoRisfw0Nm0= github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8= github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -283,15 +280,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -302,15 +296,12 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -320,9 +311,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -339,26 +327,21 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -366,10 +349,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -384,18 +363,18 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/server/api.go b/server/api.go index 2110402c..0fc078e1 100644 --- a/server/api.go +++ b/server/api.go @@ -26,6 +26,8 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req router.GET("/ai_threads", p.handleGetAIThreads) router.GET("/ai_bots", p.handleGetAIBots) + router.POST("/conversation", p.handlePostConversation) + botRequriedRouter := router.Group("") botRequriedRouter.Use(p.aiBotRequired) diff --git a/server/api_conversation.go b/server/api_conversation.go new file mode 100644 index 00000000..48960926 --- /dev/null +++ b/server/api_conversation.go @@ -0,0 +1,118 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + + "github.com/mattermost/mattermost/server/public/model" + "github.com/mattermost/mattermost/server/public/pluginapi" + + "github.com/gin-gonic/gin" +) + +func (p *Plugin) handlePostConversation(c *gin.Context) { + userID := c.GetHeader("Mattermost-User-Id") + + // We only allow bots to use this API handler for the time being. + if _, err := p.pluginAPI.Bot.Get(userID, false); errors.Is(err, pluginapi.ErrNotFound) { + c.AbortWithError(http.StatusForbidden, errors.New("forbidden")) + return + } else if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get bot: %w", err)) + return + } + + var conv []*model.Post + if err := json.NewDecoder(c.Request.Body).Decode(&conv); err != nil { + c.AbortWithError(http.StatusBadRequest, err) + return + } + defer c.Request.Body.Close() + if len(conv) == 0 { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty conversation")) + return + } + + // The last post is expected to contain the current request, everything else is used as context. + post := conv[len(conv)-1] + + if post.ChannelId == "" { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty channel id")) + return + } + + channel, err := p.pluginAPI.Channel.Get(post.ChannelId) + if errors.Is(err, pluginapi.ErrNotFound) { + c.AbortWithError(http.StatusBadRequest, errors.New("channel not found")) + return + } else if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get channel: %w", err)) + return + } + + if post.UserId == "" { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty user id")) + return + } + + postingUser, err := p.pluginAPI.User.Get(post.UserId) + if errors.Is(err, pluginapi.ErrNotFound) { + c.AbortWithError(http.StatusBadRequest, errors.New("user not found")) + return + } else if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get posting user: %w", err)) + return + } + + // Don't respond to ourselves + if p.IsAnyBot(post.UserId) { + c.AbortWithError(http.StatusBadRequest, errors.New("not responding to ourselves")) + return + } + + bot := p.GetBotMentioned(post.Message) + if bot == nil { + c.AbortWithError(http.StatusBadRequest, errors.New("missing bot mention")) + return + } + + list := &model.PostList{ + Order: make([]string, 0, len(conv)), + Posts: make(map[string]*model.Post, len(conv)), + } + for i, post := range conv { + list.Order = append(list.Order, post.Id) + list.Posts[post.Id] = conv[i] + } + + threadData, err := p.getMetadataForPosts(list) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to get thread data: %w", err)) + return + } + + result, err := p.continueConversation(bot, threadData, p.MakeConversationContext(bot, postingUser, channel, post)) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to continue conversation: %w", err)) + return + } + + for { + select { + case msg := <-result.Stream: + if _, err := c.Writer.WriteString(msg); err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("error while writing result: %w", err)) + } + // Flushing lets us stream partial results without requiring the client to wait for the full response. + c.Writer.Flush() + case err, ok := <-result.Err: + if !ok { + return + } + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("error while streaming result: %w", err)) + return + } + } +} diff --git a/server/api_test.go b/server/api_test.go index 12de6a7c..238589c1 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -1,6 +1,8 @@ package main import ( + "bytes" + "encoding/json" "io" "net/http" "net/http/httptest" @@ -298,3 +300,207 @@ func TestChannelRouter(t *testing.T) { } } } + +func TestPostConversation(t *testing.T) { + // This just makes gin not output a whole bunch of debug stuff. + // maybe pipe this to the test log? + gin.SetMode(gin.ReleaseMode) + gin.DefaultWriter = io.Discard + + url := "/conversation" + + newPayloadReader := func(conv []*model.Post) io.Reader { + data, err := json.Marshal(conv) + require.NoError(t, err) + return bytes.NewReader(data) + } + + for name, test := range map[string]struct { + request *http.Request + expectedStatus int + config Config + envSetup func(e *TestEnvironment) + }{ + "not a bot": { + request: httptest.NewRequest("POST", url, nil), + expectedStatus: http.StatusForbidden, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(nil, &model.AppError{StatusCode: http.StatusNotFound}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "failed to get bot": { + request: httptest.NewRequest("POST", url, nil), + expectedStatus: http.StatusInternalServerError, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(nil, &model.AppError{StatusCode: http.StatusInternalServerError}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "empty conv": { + request: httptest.NewRequest("POST", url, nil), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "missing channel": { + request: httptest.NewRequest("POST", url, newPayloadReader(nil)), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "channel not found": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(nil, &model.AppError{StatusCode: http.StatusNotFound}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "failure to get channel": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + }, + })), + expectedStatus: http.StatusInternalServerError, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(nil, &model.AppError{StatusCode: http.StatusInternalServerError}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "missing poster id": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "poster not found": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + UserId: "posterid", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) + e.mockAPI.On("GetUser", "posterid").Return(nil, &model.AppError{StatusCode: http.StatusNotFound}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "failure to get poster": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + UserId: "posterid", + }, + })), + expectedStatus: http.StatusInternalServerError, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) + e.mockAPI.On("GetUser", "posterid").Return(nil, &model.AppError{StatusCode: http.StatusInternalServerError}) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "not responding to ourselves": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + UserId: "botid", + Message: "@ai what time is it?", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) + e.mockAPI.On("GetUser", "botid").Return(&model.User{Id: "botid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "missing bot mention": { + request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ + { + ChannelId: "channelid", + UserId: "posterid", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) + e.mockAPI.On("GetUser", "posterid").Return(&model.User{Id: "posterid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + } { + t.Run(name, func(t *testing.T) { + e := SetupTestEnvironment(t) + defer e.Cleanup(t) + + test.config.DefaultBotName = "ai" + e.plugin.setConfiguration(makeConfig(test.config)) + + test.envSetup(e) + + test.request.Header.Add("Mattermost-User-ID", "userid") + recorder := httptest.NewRecorder() + e.plugin.ServeHTTP(&plugin.Context{}, recorder, test.request) + resp := recorder.Result() + require.Equal(t, test.expectedStatus, resp.StatusCode) + }) + } +} diff --git a/server/plugin.go b/server/plugin.go index d85f0106..a05f429b 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -175,7 +175,7 @@ const ( // handleMessages Handled messages posted. Returns true if a response was posted. func (p *Plugin) handleMessages(post *model.Post) error { - // Don't respond to ouselves + // Don't respond to ourselves if p.IsAnyBot(post.UserId) { return fmt.Errorf("not responding to ourselves: %w", ErrNoResponse) } From 7c11691c187011a125f6114aca3b4c0ca80fcccf Mon Sep 17 00:00:00 2001 From: streamer45 Date: Fri, 14 Jun 2024 17:11:56 +0200 Subject: [PATCH 2/3] Use structured request payload --- server/api_conversation.go | 54 ++++++++++++----- server/api_test.go | 120 ++++++++++++++++++++++++++----------- 2 files changed, 124 insertions(+), 50 deletions(-) diff --git a/server/api_conversation.go b/server/api_conversation.go index 48960926..b03e21cb 100644 --- a/server/api_conversation.go +++ b/server/api_conversation.go @@ -12,6 +12,15 @@ import ( "github.com/gin-gonic/gin" ) +type ConversationRequest struct { + // The name of the bot that should handle the request. + BotName string `json:"bot_name"` + // Optional past conversation to be used as context. + Thread []*model.Post `json:"thread"` + // The post to be processed in this request. + Request *model.Post `json:"request"` +} + func (p *Plugin) handlePostConversation(c *gin.Context) { userID := c.GetHeader("Mattermost-User-Id") @@ -24,19 +33,36 @@ func (p *Plugin) handlePostConversation(c *gin.Context) { return } - var conv []*model.Post - if err := json.NewDecoder(c.Request.Body).Decode(&conv); err != nil { + var reqData ConversationRequest + if err := json.NewDecoder(c.Request.Body).Decode(&reqData); err != nil { c.AbortWithError(http.StatusBadRequest, err) return } defer c.Request.Body.Close() - if len(conv) == 0 { - c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty conversation")) + + // Validation + if reqData.BotName == "" { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty bot")) return } - // The last post is expected to contain the current request, everything else is used as context. - post := conv[len(conv)-1] + bot := p.GetBotByUsername(reqData.BotName) + if bot == nil { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid bot name")) + return + } + + post := reqData.Request + + if post == nil { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid request")) + return + } + + if post.Message == "" { + c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty message")) + return + } if post.ChannelId == "" { c.AbortWithError(http.StatusBadRequest, errors.New("invalid empty channel id")) @@ -72,19 +98,15 @@ func (p *Plugin) handlePostConversation(c *gin.Context) { return } - bot := p.GetBotMentioned(post.Message) - if bot == nil { - c.AbortWithError(http.StatusBadRequest, errors.New("missing bot mention")) - return - } - list := &model.PostList{ - Order: make([]string, 0, len(conv)), - Posts: make(map[string]*model.Post, len(conv)), + Order: make([]string, 0, len(reqData.Thread)+1), + Posts: make(map[string]*model.Post, len(reqData.Thread)+1), } - for i, post := range conv { + list.Order = append(list.Order, post.Id) + list.Posts[post.Id] = post + for i, post := range reqData.Thread { list.Order = append(list.Order, post.Id) - list.Posts[post.Id] = conv[i] + list.Posts[post.Id] = reqData.Thread[i] } threadData, err := p.getMetadataForPosts(list) diff --git a/server/api_test.go b/server/api_test.go index 238589c1..d68ebd51 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -309,8 +309,8 @@ func TestPostConversation(t *testing.T) { url := "/conversation" - newPayloadReader := func(conv []*model.Post) io.Reader { - data, err := json.Marshal(conv) + newPayloadReader := func(req *ConversationRequest) io.Reader { + data, err := json.Marshal(req) require.NoError(t, err) return bytes.NewReader(data) } @@ -343,7 +343,7 @@ func TestPostConversation(t *testing.T) { e.mockAPI.On("LogError", mock.Anything).Once() }, }, - "empty conv": { + "empty request": { request: httptest.NewRequest("POST", url, nil), expectedStatus: http.StatusBadRequest, config: Config{ @@ -365,10 +365,66 @@ func TestPostConversation(t *testing.T) { e.mockAPI.On("LogError", mock.Anything).Once() }, }, + "missing bot name": { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{})), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "invalid bot": { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "invalid", + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "missing post": { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, + "empty message": { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", + }, + })), + expectedStatus: http.StatusBadRequest, + config: Config{ + EnableUseRestrictions: false, + }, + envSetup: func(e *TestEnvironment) { + e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) + e.mockAPI.On("LogError", mock.Anything).Once() + }, + }, "channel not found": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", }, })), expectedStatus: http.StatusBadRequest, @@ -382,9 +438,12 @@ func TestPostConversation(t *testing.T) { }, }, "failure to get channel": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", }, })), expectedStatus: http.StatusInternalServerError, @@ -398,9 +457,12 @@ func TestPostConversation(t *testing.T) { }, }, "missing poster id": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", }, })), expectedStatus: http.StatusBadRequest, @@ -414,9 +476,12 @@ func TestPostConversation(t *testing.T) { }, }, "poster not found": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", UserId: "posterid", }, })), @@ -432,9 +497,12 @@ func TestPostConversation(t *testing.T) { }, }, "failure to get poster": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", UserId: "posterid", }, })), @@ -450,11 +518,13 @@ func TestPostConversation(t *testing.T) { }, }, "not responding to ourselves": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { + request: httptest.NewRequest("POST", url, newPayloadReader(&ConversationRequest{ + BotName: "ai", + Request: &model.Post{ + Id: "postid", ChannelId: "channelid", + Message: "request", UserId: "botid", - Message: "@ai what time is it?", }, })), expectedStatus: http.StatusBadRequest, @@ -468,24 +538,6 @@ func TestPostConversation(t *testing.T) { e.mockAPI.On("LogError", mock.Anything).Once() }, }, - "missing bot mention": { - request: httptest.NewRequest("POST", url, newPayloadReader([]*model.Post{ - { - ChannelId: "channelid", - UserId: "posterid", - }, - })), - expectedStatus: http.StatusBadRequest, - config: Config{ - EnableUseRestrictions: false, - }, - envSetup: func(e *TestEnvironment) { - e.mockAPI.On("GetBot", "userid", false).Return(&model.Bot{UserId: "userid"}, nil) - e.mockAPI.On("GetChannel", "channelid").Return(&model.Channel{Id: "channelid"}, nil) - e.mockAPI.On("GetUser", "posterid").Return(&model.User{Id: "posterid"}, nil) - e.mockAPI.On("LogError", mock.Anything).Once() - }, - }, } { t.Run(name, func(t *testing.T) { e := SetupTestEnvironment(t) From 8043537cd70a58e6154159aaa5c2c5a2412cfd32 Mon Sep 17 00:00:00 2001 From: streamer45 Date: Fri, 14 Jun 2024 18:12:15 +0200 Subject: [PATCH 3/3] Allow overriding role --- server/api_conversation.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/server/api_conversation.go b/server/api_conversation.go index b03e21cb..e21c2f8a 100644 --- a/server/api_conversation.go +++ b/server/api_conversation.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" + "github.com/mattermost/mattermost-plugin-ai/server/ai" + "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/pluginapi" @@ -19,6 +21,8 @@ type ConversationRequest struct { Thread []*model.Post `json:"thread"` // The post to be processed in this request. Request *model.Post `json:"request"` + // Whether to use the system role to generate the prompt. + UseSystemRole bool `json:"use_system_role"` } func (p *Plugin) handlePostConversation(c *gin.Context) { @@ -115,9 +119,23 @@ func (p *Plugin) handlePostConversation(c *gin.Context) { return } - result, err := p.continueConversation(bot, threadData, p.MakeConversationContext(bot, postingUser, channel, post)) + prompt, err := p.prompts.ChatCompletion(ai.PromptDirectMessageQuestion, p.MakeConversationContext(bot, postingUser, channel, post)) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to generate prompt: %w", err)) + return + } + prompt.AppendConversation(p.ThreadToBotConversation(bot, threadData.Posts)) + + // Overriding post role if requested. + if reqData.UseSystemRole { + for i := range prompt.Posts { + prompt.Posts[i].Role = ai.PostRoleSystem + } + } + + result, err := p.getLLM(bot.cfg).ChatCompletion(prompt) if err != nil { - c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to continue conversation: %w", err)) + c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to process request: %w", err)) return }