427 lines
10 KiB
TypeScript
427 lines
10 KiB
TypeScript
|
import axios from "axios";
|
||
|
import { z } from "zod";
|
||
|
import { zodFunction } from ".";
|
||
|
import { RunnableToolFunction } from "openai/lib/RunnableFunction.mjs";
|
||
|
import { ask } from "./ask";
|
||
|
import { Message } from "../interfaces/message";
|
||
|
import { memory_manager_guide, memory_manager_init } from "./memory-manager";
|
||
|
|
||
|
const apiClient = axios.create({
|
||
|
baseURL: "https://link.raj.how/api/v1",
|
||
|
headers: {
|
||
|
"Content-Type": "application/json",
|
||
|
Authorization: `Bearer ${process.env.LINKWARDEN_API_KEY}`,
|
||
|
},
|
||
|
});
|
||
|
|
||
|
// Schemas for each function's parameters
|
||
|
export const ArchivedFileParams = z.object({
|
||
|
id: z.string(),
|
||
|
format: z.string().optional(),
|
||
|
});
|
||
|
export type ArchivedFileParams = z.infer<typeof ArchivedFileParams>;
|
||
|
|
||
|
export const TagParams = z.object({
|
||
|
id: z.string(),
|
||
|
});
|
||
|
export type TagParams = z.infer<typeof TagParams>;
|
||
|
|
||
|
export const TagUpdateParams = z.object({
|
||
|
id: z.string(),
|
||
|
name: z.string().optional(),
|
||
|
color: z.string().optional(),
|
||
|
});
|
||
|
export type TagUpdateParams = z.infer<typeof TagUpdateParams>;
|
||
|
|
||
|
export const CollectionParams = z.object({
|
||
|
id: z.string(),
|
||
|
});
|
||
|
export type CollectionParams = z.infer<typeof CollectionParams>;
|
||
|
|
||
|
export const CollectionLinksParams = z.object({
|
||
|
collectionId: z.string(),
|
||
|
tag: z.string().optional(),
|
||
|
sortBy: z.string().optional(),
|
||
|
limit: z.number().optional(),
|
||
|
});
|
||
|
export type CollectionLinksParams = z.infer<typeof CollectionLinksParams>;
|
||
|
|
||
|
export const ProfileParams = z.object({
|
||
|
id: z.string(),
|
||
|
});
|
||
|
export type ProfileParams = z.infer<typeof ProfileParams>;
|
||
|
|
||
|
export const MigrationParams = z.object({
|
||
|
data: z.string(),
|
||
|
});
|
||
|
export type MigrationParams = z.infer<typeof MigrationParams>;
|
||
|
|
||
|
export const LinksParams = z.object({
|
||
|
collectionId: z.string().optional(),
|
||
|
tag: z.string().optional(),
|
||
|
sortBy: z.string().optional(),
|
||
|
limit: z.number().optional(),
|
||
|
});
|
||
|
export type LinksParams = z.infer<typeof LinksParams>;
|
||
|
|
||
|
export const LinkParams = z.object({
|
||
|
id: z.string(),
|
||
|
});
|
||
|
export type LinkParams = z.infer<typeof LinkParams>;
|
||
|
|
||
|
export const LinkUpdateParams = z.object({
|
||
|
id: z.string(),
|
||
|
title: z.string().optional(),
|
||
|
url: z.string().optional(),
|
||
|
description: z.string().optional(),
|
||
|
tagIds: z.array(z.string()).optional(),
|
||
|
});
|
||
|
export type LinkUpdateParams = z.infer<typeof LinkUpdateParams>;
|
||
|
|
||
|
export const ProfilePhotoParams = z.object({
|
||
|
id: z.string(),
|
||
|
});
|
||
|
export type ProfilePhotoParams = z.infer<typeof ProfilePhotoParams>;
|
||
|
|
||
|
// Functions
|
||
|
export async function getArchivedFile({ id, format }: ArchivedFileParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/archives/${id}`, {
|
||
|
params: { format },
|
||
|
});
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getAllTags() {
|
||
|
try {
|
||
|
const response = await apiClient.get("/tags");
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function updateTag({ id, name, color }: TagUpdateParams) {
|
||
|
try {
|
||
|
const response = await apiClient.put(`/tags/${id}`, { name, color });
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function deleteTag({ id }: TagParams) {
|
||
|
try {
|
||
|
const response = await apiClient.delete(`/tags/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getPublicCollectionInfo({ id }: CollectionParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/public/collections/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getLinksUnderPublicCollection({
|
||
|
collectionId,
|
||
|
tag,
|
||
|
sortBy,
|
||
|
limit,
|
||
|
}: CollectionLinksParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get("/public/collections/links", {
|
||
|
params: { collectionId, tag, sortBy, limit },
|
||
|
});
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getSingleLinkUnderPublicCollection({ id }: LinkParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/public/links/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getPublicProfileInfo({ id }: ProfileParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/public/users/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function importData({ data }: MigrationParams) {
|
||
|
try {
|
||
|
const response = await apiClient.post("/migration", { data });
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function exportData({ data }: MigrationParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get("/migration", { params: { data } });
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getLinks({
|
||
|
collectionId,
|
||
|
tag,
|
||
|
sortBy,
|
||
|
limit,
|
||
|
}: LinksParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get("/links", {
|
||
|
params: { collectionId, tag, sortBy, limit },
|
||
|
});
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getLink({ id }: LinkParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/links/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Schema for adding a link
|
||
|
export const AddLinkParams = z.object({
|
||
|
url: z.string(),
|
||
|
name: z.string(),
|
||
|
type: z.string(),
|
||
|
tags: z.array(
|
||
|
z.object({
|
||
|
name: z.string(),
|
||
|
})
|
||
|
),
|
||
|
collection: z.object({
|
||
|
id: z.number().default(8).optional(),
|
||
|
}),
|
||
|
});
|
||
|
export type AddLinkParams = z.infer<typeof AddLinkParams>;
|
||
|
|
||
|
// Function to add a link
|
||
|
export async function addLink(params: AddLinkParams) {
|
||
|
try {
|
||
|
const response = await apiClient.post("/links", params);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
console.error(error);
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function updateLink({
|
||
|
id,
|
||
|
title,
|
||
|
url,
|
||
|
description,
|
||
|
tagIds,
|
||
|
}: LinkUpdateParams) {
|
||
|
try {
|
||
|
const response = await apiClient.put(`/links/${id}`, {
|
||
|
title,
|
||
|
url,
|
||
|
description,
|
||
|
tagIds,
|
||
|
});
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function deleteLink({ id }: LinkParams) {
|
||
|
try {
|
||
|
const response = await apiClient.delete(`/links/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function triggerArchiveForLink({ id }: LinkParams) {
|
||
|
try {
|
||
|
const response = await apiClient.put(`/links/${id}/archive`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getDashboardData() {
|
||
|
try {
|
||
|
const response = await apiClient.get("/dashboard");
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getCollections() {
|
||
|
try {
|
||
|
const response = await apiClient.get("/collections");
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export async function getProfilePhoto({ id }: ProfilePhotoParams) {
|
||
|
try {
|
||
|
const response = await apiClient.get(`/avatar/${id}`);
|
||
|
return response.data;
|
||
|
} catch (error) {
|
||
|
return `Error: ${error}`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export let link_tools: RunnableToolFunction<any>[] = [
|
||
|
zodFunction({
|
||
|
function: getAllTags,
|
||
|
name: "linkwardenGetAllTags",
|
||
|
schema: z.object({}),
|
||
|
description: "Get all tags for the user.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: updateTag,
|
||
|
name: "linkwardenUpdateTag",
|
||
|
schema: TagUpdateParams,
|
||
|
description: "Update a tag.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: deleteTag,
|
||
|
name: "linkwardenDeleteTag",
|
||
|
schema: TagParams,
|
||
|
description: "Delete a tag.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getPublicCollectionInfo,
|
||
|
name: "linkwardenGetPublicCollectionInfo",
|
||
|
schema: CollectionParams,
|
||
|
description: "Get public collection info.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getLinksUnderPublicCollection,
|
||
|
name: "linkwardenGetLinksUnderPublicCollection",
|
||
|
schema: CollectionLinksParams,
|
||
|
description: "Get links under a public collection.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getSingleLinkUnderPublicCollection,
|
||
|
name: "linkwardenGetSingleLinkUnderPublicCollection",
|
||
|
schema: LinkParams,
|
||
|
description: "Get a single link under a public collection.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getPublicProfileInfo,
|
||
|
name: "linkwardenGetPublicProfileInfo",
|
||
|
schema: ProfileParams,
|
||
|
description: "Get public profile info.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getLinks,
|
||
|
name: "linkwardenGetLinks",
|
||
|
schema: LinksParams,
|
||
|
description: "Get links under a collection.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getLink,
|
||
|
name: "linkwardenGetLink",
|
||
|
schema: LinkParams,
|
||
|
description: "Get a single link under a collection.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: updateLink,
|
||
|
name: "linkwardenUpdateLink",
|
||
|
schema: LinkUpdateParams,
|
||
|
description: "Update a link.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: addLink,
|
||
|
name: "linkwardenAddLink",
|
||
|
schema: AddLinkParams,
|
||
|
description:
|
||
|
"Add a link (default to 'Anya' collection with id=8 if not specified).",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: deleteLink,
|
||
|
name: "linkwardenDeleteLink",
|
||
|
schema: LinkParams,
|
||
|
description: "Delete a link.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: triggerArchiveForLink,
|
||
|
name: "linkwardenTriggerArchiveForLink",
|
||
|
schema: LinkParams,
|
||
|
description: "Trigger archive for a link.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getDashboardData,
|
||
|
name: "linkwardenGetDashboardData",
|
||
|
schema: z.object({}),
|
||
|
description: "Get dashboard data.",
|
||
|
}),
|
||
|
zodFunction({
|
||
|
function: getCollections,
|
||
|
name: "linkwardenGetCollections",
|
||
|
schema: z.object({}),
|
||
|
description: "Get all collections for the user.",
|
||
|
}),
|
||
|
];
|
||
|
|
||
|
export const LinkManagerParams = z.object({
|
||
|
request: z
|
||
|
.string()
|
||
|
.describe("User's request regarding links, tags, or collections."),
|
||
|
});
|
||
|
export type LinkManagerParams = z.infer<typeof LinkManagerParams>;
|
||
|
|
||
|
export async function linkManager(
|
||
|
{ request }: LinkManagerParams,
|
||
|
context_message: Message
|
||
|
) {
|
||
|
const response = await ask({
|
||
|
model: "gpt-4o-mini",
|
||
|
prompt: `You are a Linkwarden manager.
|
||
|
|
||
|
Your job is to understand the user's request and manage links, tags, or collections using the available tools.
|
||
|
|
||
|
----
|
||
|
${memory_manager_guide("links_manager")}
|
||
|
----
|
||
|
`,
|
||
|
message: request,
|
||
|
seed: "link-${context_message.channelId}",
|
||
|
tools: link_tools.concat(
|
||
|
memory_manager_init(context_message, "links_manager")
|
||
|
) as any,
|
||
|
});
|
||
|
|
||
|
return { response };
|
||
|
}
|