-
Notifications
You must be signed in to change notification settings - Fork 2.5k
community[minor]: Taskade Project Loader #5927
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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> | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { TaskadeProjectLoader } from "@langchain/community/document_loaders/web/taskade"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey there! I noticed that the recent change in the |
||
|
||
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 }); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/* eslint-disable no-process-env */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
/* 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); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { getEnvironmentVariable } from "@langchain/core/utils/env"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
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 })]; | ||
} | ||
} |
There was a problem hiding this comment.
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!