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

community[minor]: Taskade Project Loader #5927

Merged
merged 2 commits into from
Jul 2, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
hide_table_of_contents: true
---

# Taskade

[Taskade](https://www.taskade.com) is the ultimate tool for AI-driven writing, project management, and task automation. Designed to be your second brain, Taskade simplifies project execution and enhances team collaboration from start to finish.

## Overview

With [Taskade](https://www.taskade.com), you can build, train, and deploy your own team of AI agents to automate tasks and streamline workflows. Taskade features a seamless blend of ideation, collaboration, and execution tools—from structured lists to modern tables and mind maps, all customizable to fit your unique workflow and adapt to your needs.

import CodeBlock from "@theme/CodeBlock";
import Example from "@examples/document_loaders/taskade.ts";

<CodeBlock language="typescript">{Example}</CodeBlock>

You can find your Taskade project id by opening the project in your browser and extracting them from the URL:

```
https://www.taskade.com/d/<YOUR PROJECT ID HERE>
```
9 changes: 9 additions & 0 deletions examples/src/document_loaders/taskade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TaskadeProjectLoader } from "@langchain/community/document_loaders/web/taskade";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! I noticed that this PR adds a new external HTTP request using fetch or axios in the TaskadeProjectLoader. I've flagged this for your review to ensure it aligns with the project's requirements. Let me know if you have any questions!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! I noticed that the recent change in the taskade.ts file suggests accessing an environment variable for the personalAccessToken. I've flagged this for your review to ensure it aligns with our best practices. Let me know if you have any questions!


const loader = new TaskadeProjectLoader({
personalAccessToken: "TASKADE_PERSONAL_ACCESS_TOKEN", // or load it from process.env.TASKADE_PERSONAL_ACCESS_TOKEN
projectId: "projectId",
});
const docs = await loader.load();

console.log({ docs });
4 changes: 4 additions & 0 deletions libs/langchain-community/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,10 @@ document_loaders/web/github.cjs
document_loaders/web/github.js
document_loaders/web/github.d.ts
document_loaders/web/github.d.cts
document_loaders/web/taskade.cjs
document_loaders/web/taskade.js
document_loaders/web/taskade.d.ts
document_loaders/web/taskade.d.cts
document_loaders/web/notionapi.cjs
document_loaders/web/notionapi.js
document_loaders/web/notionapi.d.ts
Expand Down
2 changes: 2 additions & 0 deletions libs/langchain-community/langchain.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ export const config = {
"document_loaders/web/figma": "document_loaders/web/figma",
"document_loaders/web/firecrawl": "document_loaders/web/firecrawl",
"document_loaders/web/github": "document_loaders/web/github",
"document_loaders/web/taskade": "document_loaders/web/taskade",
"document_loaders/web/notionapi": "document_loaders/web/notionapi",
"document_loaders/web/pdf": "document_loaders/web/pdf",
"document_loaders/web/recursive_url": "document_loaders/web/recursive_url",
Expand Down Expand Up @@ -491,6 +492,7 @@ export const config = {
"document_loaders/web/firecrawl",
"document_loaders/web/github",
"document_loaders/web/pdf",
"document_loaders/web/taskade",
"document_loaders/web/notionapi",
"document_loaders/web/recursive_url",
"document_loaders/web/s3",
Expand Down
13 changes: 13 additions & 0 deletions libs/langchain-community/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2734,6 +2734,15 @@
"import": "./document_loaders/web/github.js",
"require": "./document_loaders/web/github.cjs"
},
"./document_loaders/web/taskade": {
"types": {
"import": "./document_loaders/web/taskade.d.ts",
"require": "./document_loaders/web/taskade.d.cts",
"default": "./document_loaders/web/taskade.d.ts"
},
"import": "./document_loaders/web/taskade.js",
"require": "./document_loaders/web/taskade.cjs"
},
"./document_loaders/web/notionapi": {
"types": {
"import": "./document_loaders/web/notionapi.d.ts",
Expand Down Expand Up @@ -3948,6 +3957,10 @@
"document_loaders/web/github.js",
"document_loaders/web/github.d.ts",
"document_loaders/web/github.d.cts",
"document_loaders/web/taskade.cjs",
"document_loaders/web/taskade.js",
"document_loaders/web/taskade.d.ts",
"document_loaders/web/taskade.d.cts",
"document_loaders/web/notionapi.cjs",
"document_loaders/web/notionapi.js",
"document_loaders/web/notionapi.d.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable no-process-env */
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! I noticed that this PR adds a test case that explicitly accesses environment variables via process.env. I've flagged this for your review to ensure proper handling of environment variables. Let me know if you have any questions or need further assistance!

/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { test } from "@jest/globals";
import { TaskadeProjectLoader } from "../web/taskade.js";

test.skip("Test TaskadeProjectLoader", async () => {
const loader = new TaskadeProjectLoader({
personalAccessToken: process.env.TASKADE_PERSONAL_ACCESS_TOKEN!,
projectId: process.env.TASKADE_PROJECT_ID!,
});
const documents = await loader.load();
console.log(documents[0].pageContent);
});
125 changes: 125 additions & 0 deletions libs/langchain-community/src/document_loaders/web/taskade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { getEnvironmentVariable } from "@langchain/core/utils/env";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! I've reviewed the code changes, and it looks like the TaskadeProjectLoader class introduces a new external HTTP request using the fetch API to fetch project tasks from the Taskade API. I've flagged this change for your review to ensure it aligns with the project's requirements. Let me know if you have any questions or need further clarification!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey team, I've flagged a change in the PR that explicitly accesses an environment variable using the getEnvironmentVariable function. This is to ensure the maintainers review and validate the handling of environment variables in the code.

import { Document } from "@langchain/core/documents";
import { BaseDocumentLoader } from "@langchain/core/document_loaders/base";

/**
* Interface representing the parameters for configuring the TaskadeLoader.
* It includes optional properties for the personal access token and project id.
*/
export interface TaskadeLoaderParams {
personalAccessToken?: string;
projectId: string;
}

/**
* Interface representing a Taskade project. It includes properties for the
* id, text, parentId and completed.
*/
export interface TaskadeProject {
tasks: Array<{
id: string;
text: string;
parentId: string;
completed: boolean;
}>;
}

/**
* Class representing a document loader for loading Taskade project. It
* extends the BaseDocumentLoader and implements the TaskadeLoaderParams
* interface. The constructor takes a config object as a parameter, which
* contains the personal access token and project ID.
* @example
* ```typescript
* const loader = new TaskadeProjectLoader({
* personalAccessToken: "TASKADE_PERSONAL_ACCESS_TOKEN",
* projectId: "projectId",
* });
* const docs = await loader.load();
* ```
*/
export class TaskadeProjectLoader
extends BaseDocumentLoader
implements TaskadeLoaderParams
{
public readonly personalAccessToken?: string;

public readonly projectId: string;

private headers: Record<string, string> = {};

constructor({
personalAccessToken = getEnvironmentVariable(
"TASKADE_PERSONAL_ACCESS_TOKEN"
),
projectId,
}: TaskadeLoaderParams) {
super();
this.personalAccessToken = personalAccessToken;
this.projectId = projectId;

if (this.personalAccessToken) {
this.headers = {
Authorization: `Bearer ${this.personalAccessToken}`,
};
}
}

/**
* Fetches the Taskade project using the Taskade API and returns it as a
* TaskadeProject object.
* @returns A Promise that resolves to a TaskadeProject object.
*/
private async getTaskadeProject(): Promise<TaskadeProject> {
const tasks = [];
let after: string | null = null;
let hasMoreTasks = true;
while (hasMoreTasks) {
const queryParamsString: string = new URLSearchParams({
limit: "100",
...(after == null ? {} : { after }),
}).toString();
const url = `https://www.taskade.com/api/v1/projects/${this.projectId}/tasks?${queryParamsString}`;

const response = await fetch(url, { headers: this.headers });
const data = await response.json();

if (!response.ok) {
throw new Error(
`Unable to get Taskade project: ${response.status} ${JSON.stringify(
data
)}`
);
}

if (!data) {
throw new Error("Unable to get Taskade project");
}

if (data.items.length === 0) {
hasMoreTasks = false;
} else {
after = data.items[data.items.length - 1].id;
}

tasks.push(...data.items);
}

return { tasks };
}

/**
* Fetches the Taskade project using the Taskade API, creates a Document instance
* with the JSON representation of the file as the page content and the
* API URL as the metadata, and returns it.
* @returns A Promise that resolves to an array of Document instances.
*/
public async load(): Promise<Document[]> {
const data = await this.getTaskadeProject();

const metadata = { projectId: this.projectId };
const text = data.tasks.map((t) => t.text).join("\n");

return [new Document({ pageContent: text, metadata })];
}
}
1 change: 1 addition & 0 deletions libs/langchain-community/src/load/import_constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export const optionalImportEntrypoints: string[] = [
"langchain_community/document_loaders/web/figma",
"langchain_community/document_loaders/web/firecrawl",
"langchain_community/document_loaders/web/github",
"langchain_community/document_loaders/web/taskade",
"langchain_community/document_loaders/web/notionapi",
"langchain_community/document_loaders/web/pdf",
"langchain_community/document_loaders/web/recursive_url",
Expand Down
Loading