Skip to content

Commit 83cd749

Browse files
Tools: sharepoint tool (#929)
* feat(backend): added sharepoint tool * feat(web_assistant): added sharepoint tool * chore(backend): removed session from args in tool call * chore(community): cleanup community tool call --------- Co-authored-by: EugeneP <eugene@lightsonsoftware.com>
1 parent 29f614e commit 83cd749

File tree

36 files changed

+705
-94
lines changed

36 files changed

+705
-94
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Toolkit is a deployable all-in-one RAG application that enables users to quickly
1616
- [How to setup Gmail](/docs/custom_tool_guides/gmail.md)
1717
- [How to setup Slack Tool](/docs/custom_tool_guides/slack.md)
1818
- [How to setup Github Tool](/docs/custom_tool_guides/github.md)
19+
- [How to setup Sharepoint](/docs/custom_tool_guides/sharepoint.md)
1920
- [How to setup Google Text-to-Speech](/docs/text_to_speech.md)
2021
- [How to add authentication](/docs/auth_guide.md)
2122
- [How to deploy toolkit services](/docs/service_deployments.md)
@@ -28,30 +29,39 @@ Toolkit is a deployable all-in-one RAG application that enables users to quickly
2829
![](/docs/assets/toolkit.gif)
2930

3031
## Try Now:
31-
There are two main ways for quickly running Toolkit: local and cloud. See the specific instructions given below.
32+
33+
There are two main ways for quickly running Toolkit: local and cloud. See the specific instructions given below.
34+
3235
### Local
33-
*You will need to have [Docker](https://www.docker.com/products/docker-desktop/), [Docker-compose >= 2.22](https://docs.docker.com/compose/install/), and [Poetry](https://python-poetry.org/docs/#installation) installed. [Go here for a more detailed setup.](/docs/setup.md)*
36+
37+
_You will need to have [Docker](https://www.docker.com/products/docker-desktop/), [Docker-compose >= 2.22](https://docs.docker.com/compose/install/), and [Poetry](https://python-poetry.org/docs/#installation) installed. [Go here for a more detailed setup.](/docs/setup.md)_
3438
Note: to include community tools when building locally, set the `INSTALL_COMMUNITY_DEPS` build arg in the `docker-compose.yml` to `true`.
3539

3640
Both options will serve the frontend at http://localhost:4000.
3741

3842
#### Using `make`
43+
3944
Use the provided Makefile to simplify and automate your development workflow with Cohere Toolkit, including Docker Compose management, testing, linting, and environment setup.
45+
4046
```bash
4147
git clone https://github.com/cohere-ai/cohere-toolkit.git
4248
cd cohere-toolkit
4349
make first-run
4450
```
4551

4652
#### Docker Compose only
53+
4754
Use Docker Compose directly if you want to quickly spin up and manage your container environment without the additional automation provided by the Makefile.
55+
4856
```bash
4957
git clone https://github.com/cohere-ai/cohere-toolkit.git
5058
cd cohere-toolkit
5159
docker compose up
5260
docker compose run --build backend alembic -c src/backend/alembic.ini upgrade head
5361
```
62+
5463
### Cloud
64+
5565
#### GitHub Codespaces
5666

5767
To run this project using GitHub Codespaces, please refer to our [Codespaces Setup Guide](/docs/github_codespaces.md).
@@ -63,7 +73,7 @@ To run this project using GitHub Codespaces, please refer to our [Codespaces Set
6373
- **Interfaces** - any client-side UI, currently contains two web apps, one agentic and one basic, and a Slack bot implementation.
6474
- Defaults to Cohere's Web UI at `src/interfaces/assistants_web` - A web app built in Next.js. Includes a simple SQL database out of the box to store conversation history in the app.
6575
- You can change the Web UI using the docker compose file.
66-
- **Backend API** - in `src/backend` this follows a similar structure to the [Cohere Chat API](https://docs.cohere.com/reference/chat) but also include customizable elements:
76+
- **Backend API** - in `src/backend` this follows a similar structure to the [Cohere Chat API](https://docs.cohere.com/reference/chat) but also include customizable elements:
6777
- **Model** - you can customize with which provider you access Cohere's Command models. By default included in the toolkit is Cohere's Platform, Sagemaker, Azure, Bedrock, HuggingFace, local models. [More details here.](/docs/command_model_providers.md)
6878
- **Retrieval**- you can customize tools and data sources that the application is run with.
6979
- **Service Deployment Guides** - we also include guides for how to deploy the toolkit services in production including with AWS, GCP and Azure. [More details here.](/docs/service_deployments.md)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Sharepoint Tool Setup
2+
3+
To setup the Sharepoint tool you need to configure API access via the following steps
4+
5+
## 1. Configure Tenant ID and Client ID
6+
7+
Your Microsoft Tenant ID and Client ID can be found my navigating to the [Micorsoft Entra Admin Center](https://entra.microsoft.com/) and then going to the `Overview` Page under the `Identity Section`. There the Tenant ID is listed as Tenant ID, and the Client ID is listed as the Application ID.
8+
9+
Copy your Tenant ID into the `configuration.yaml` file in the config directory of the backend, and your Client ID into the `secrets.yaml` file in the config directory of the backend.
10+
11+
## 2. Register New Application
12+
13+
Navigate to the `App registration` page under `Applications` on the same [Micorsoft Entra Admin Center](https://entra.microsoft.com/) website.
14+
15+
Click `New registration` to register a new application. Enter a name and select the proper account type. Single tenant is the norm unless you know of otherwise.
16+
17+
Under redirect URI select Web as the path should be `/v1/tool/auth`. For example:
18+
19+
```bash
20+
https://<your_backend_url>/v1/tool/auth
21+
```
22+
23+
Click `Register` to Complete the Application Registration
24+
25+
## 3. Configure Permissions
26+
27+
Under the newly registered application navigate to the `API permissions` page. There you need to Click `Add a permission`, select `Microsoft Graph`, then `delegated permissions`. Next search `files.read.all` and check the box, then search `sites.read.all` and check the box. Then Click `Add permissions`.
28+
29+
## 3. Configure Client Secret
30+
31+
Under the newly registered application navigate to the `Certificates & secrets` page. Click `New client secret`, enter a description and an expiry then click `Add`. Your new Client Secret is only available to copy under the `value` column of the table right now. Copy it into the `secrets.yaml` file in the config directory of the backend.
32+
33+
## 5. Run the Backend and Frontend
34+
35+
run next command to start the backend and frontend:
36+
37+
```bash
38+
make dev
39+
```

src/backend/config/configuration.template.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ tools:
4242
- public_repo
4343
default_repos:
4444
- cohere-ai/cohere-toolkit
45-
- EugeneLightsOn/cohere-toolkit
45+
sharepoint:
46+
tenant_id:
4647
# To disable the use of the tools preamble, set it to false
4748
use_tools_preamble: true
4849
feature_flags:

src/backend/config/secrets.template.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ tools:
4040
github:
4141
client_id:
4242
client_secret:
43+
sharepoint:
44+
client_id:
45+
client_secret:
4346
auth:
4447
secret_key:
4548
google_oauth:
@@ -53,4 +56,4 @@ auth:
5356
client_secret:
5457
well_known_endpoint:
5558
google_cloud:
56-
api_key:
59+
api_key:

src/backend/config/settings.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ class HybridWebSearchSettings(BaseSettings, BaseModel):
271271
site_filters: Optional[List[str]] = []
272272

273273

274+
class SharepointSettings(BaseSettings, BaseModel):
275+
model_config = SETTINGS_CONFIG
276+
tenant_id: Optional[str] = Field(
277+
default=None,
278+
validation_alias=AliasChoices("SHAREPOINT_TENANT_ID", "tenant_id"),
279+
)
280+
client_id: Optional[str] = Field(
281+
default=None,
282+
validation_alias=AliasChoices("SHAREPOINT_CLIENT_ID", "client_id"),
283+
)
284+
client_secret: Optional[str] = Field(
285+
default=None,
286+
validation_alias=AliasChoices("SHAREPOINT_CLIENT_SECRET", "client_secret"),
287+
)
288+
289+
274290
class ToolSettings(BaseSettings, BaseModel):
275291
model_config = SETTINGS_CONFIG
276292

@@ -302,6 +318,9 @@ class ToolSettings(BaseSettings, BaseModel):
302318
gmail: Optional[GmailSettings] = Field(
303319
default=GmailSettings()
304320
)
321+
sharepoint: Optional[SharepointSettings] = Field(
322+
default=SharepointSettings()
323+
)
305324
use_tools_preamble: Optional[bool] = Field(
306325
default=False,
307326
validation_alias=AliasChoices("USE_TOOLS_PREAMBLE", "use_tools_preamble")

src/backend/config/tools.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
PythonInterpreter,
1515
ReadFileTool,
1616
SearchFileTool,
17+
SharepointTool,
1718
SlackTool,
1819
TavilyWebSearch,
1920
WebScrapeTool,
@@ -40,6 +41,7 @@ class Tool(Enum):
4041
Slack = SlackTool
4142
Gmail = GmailTool
4243
Github = GithubTool
44+
Sharepoint = SharepointTool
4345

4446

4547
def get_available_tools() -> dict[str, ToolDefinition]:

src/backend/tests/unit/tools/test_lang_chain.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,13 @@ async def test_wiki_retriever_no_docs() -> None:
7272
):
7373
result = await retriever.call({"query": query}, ctx)
7474

75-
assert result == [ToolError(type=ToolErrorCode.OTHER, success=False, text='No results found.', details='No results found for the given params.').model_dump()]
75+
expected_error = ToolError(
76+
type=ToolErrorCode.OTHER,
77+
success=False,
78+
text='No results found.',
79+
details='No results found for the given params.'
80+
).model_dump()
81+
assert result == [expected_error]
7682

7783

7884

@@ -156,4 +162,10 @@ async def test_vector_db_retriever_no_docs() -> None:
156162
mock_db.as_retriever().get_relevant_documents.return_value = mock_docs
157163
result = await retriever.call({"query": query}, ctx)
158164

159-
assert result == [ToolError(type=ToolErrorCode.OTHER, success=False, text='No results found.', details='No results found for the given params.').model_dump()]
165+
expected_error = ToolError(
166+
type=ToolErrorCode.OTHER,
167+
success=False,
168+
text='No results found.',
169+
details='No results found for the given params.'
170+
).model_dump()
171+
assert result == [expected_error]

src/backend/tools/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from backend.tools.brave_search import BraveWebSearch
22
from backend.tools.calculator import Calculator
33
from backend.tools.files import ReadFileTool, SearchFileTool
4+
from backend.tools.github import GithubAuth, GithubTool
45
from backend.tools.gmail import GmailAuth, GmailTool
56
from backend.tools.google_drive import GoogleDrive, GoogleDriveAuth
67
from backend.tools.google_search import GoogleWebSearch
78
from backend.tools.hybrid_search import HybridWebSearch
89
from backend.tools.lang_chain import LangChainVectorDBRetriever, LangChainWikiRetriever
910
from backend.tools.python_interpreter import PythonInterpreter
11+
from backend.tools.sharepoint import SharepointAuth, SharepointTool
1012
from backend.tools.slack import SlackAuth, SlackTool
1113
from backend.tools.tavily_search import TavilyWebSearch
1214
from backend.tools.web_scrape import WebScrapeTool
@@ -29,4 +31,8 @@
2931
"SlackAuth",
3032
"GmailTool",
3133
"GmailAuth",
34+
"SharepointTool",
35+
"SharepointAuth",
36+
"GithubTool",
37+
"GithubAuth",
3238
]

src/backend/tools/base.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import datetime
22
from abc import ABC, abstractmethod
33
from enum import StrEnum
4-
from typing import Any, Dict, List
4+
from typing import Any
55

66
import requests
77
from fastapi import Request
@@ -11,6 +11,7 @@
1111
from backend.crud import tool_auth as tool_auth_crud
1212
from backend.database_models.database import DBSessionDep
1313
from backend.database_models.tool_auth import ToolAuth
14+
from backend.schemas.context import Context
1415
from backend.schemas.tool import ToolDefinition
1516
from backend.services.logger.utils import LoggerFactory
1617
from backend.tools.utils.tools_checkers import check_tool_parameters
@@ -157,20 +158,22 @@ def _handle_tool_specific_errors(cls, error: Exception, **kwargs: Any) -> None:
157158
...
158159

159160
@classmethod
160-
def get_tool_error(cls, details: str, text: str = "Error calling tool", error_type: ToolErrorCode = ToolErrorCode.OTHER):
161+
def get_tool_error(
162+
cls, details: str, text: str = "Error calling tool", error_type: ToolErrorCode = ToolErrorCode.OTHER,
163+
) -> list[dict[str, str]]:
161164
tool_error = ToolError(text=f"{text} {cls.ID}.", details=details, type=error_type).model_dump()
162165
logger.error(event=f"Error calling tool {cls.ID}", error=tool_error)
163166
return [tool_error]
164167

165168
@classmethod
166-
def get_no_results_error(cls):
169+
def get_no_results_error(cls) -> list[dict[str, str]]:
167170
tool_error = ToolError(text="No results found.", details="No results found for the given params.").model_dump()
168171
return [tool_error]
169172

170173
@abstractmethod
171174
async def call(
172-
self, parameters: dict, ctx: Any, **kwargs: Any
173-
) -> List[Dict[str, Any]]:
175+
self, parameters: dict, ctx: Context, **kwargs: Any,
176+
) -> list[dict[str, Any]]:
174177
...
175178

176179
@classmethod
@@ -248,7 +251,7 @@ def try_refresh_token(
248251
@abstractmethod
249252
def retrieve_auth_token(
250253
self, request: Request, session: DBSessionDep, user_id: str
251-
) -> str:
254+
) -> str|None:
252255
...
253256

254257
def get_token(self, session: DBSessionDep, user_id: str) -> str:

src/backend/tools/brave_search/tool.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from typing import Any, Dict, List
1+
from typing import Any
22

33
from backend.config.settings import Settings
4-
from backend.database_models.database import DBSessionDep
4+
from backend.schemas.context import Context
55
from backend.schemas.tool import ToolCategory, ToolDefinition
66
from backend.tools.base import BaseTool, ToolArgument
77
from backend.tools.brave_search.client import BraveClient
@@ -40,11 +40,11 @@ def get_tool_definition(cls) -> ToolDefinition:
4040
"Returns a list of relevant document snippets for a textual query retrieved "
4141
"from the internet using Brave Search."
4242
),
43-
)
43+
) # type: ignore
4444

4545
async def call(
46-
self, parameters: dict, ctx: Any, session: DBSessionDep, **kwargs: Any
47-
) -> List[Dict[str, Any]]:
46+
self, parameters: dict, ctx: Context, **kwargs: Any
47+
) -> list[dict[str, Any]]:
4848
query = parameters.get("query", "")
4949

5050
# Get domain filtering from kwargs

0 commit comments

Comments
 (0)