mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(obsidian): add Obsidian integration with 15 tools (#3455)
* feat(obsidian): add Obsidian integration with 15 tools * fix(obsidian): encode path segments individually to preserve slashes * improvement(obsidian): add type re-exports and improve output descriptions * fix(obsidian): remove unreachable 404 handling from transformResponse
This commit is contained in:
@@ -710,6 +710,155 @@ export function PerplexityIcon(props: SVGProps<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function ObsidianIcon(props: SVGProps<SVGSVGElement>) {
|
||||
const id = useId()
|
||||
const bl = `${id}-bl`
|
||||
const tr = `${id}-tr`
|
||||
const tl = `${id}-tl`
|
||||
const br = `${id}-br`
|
||||
const te = `${id}-te`
|
||||
const le = `${id}-le`
|
||||
const be = `${id}-be`
|
||||
const me = `${id}-me`
|
||||
const clip = `${id}-clip`
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 512 512' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<radialGradient
|
||||
id={bl}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-59 -225 150 -39 161.4 470)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.4' />
|
||||
<stop offset='1' stopOpacity='.1' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={tr}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(50 -379 280 37 360 374.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.6' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.1' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={tl}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(69 -319 218 47 175.4 307)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.8' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.4' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={br}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-96 -163 187 -111 335.3 512.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.3' />
|
||||
<stop offset='1' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={te}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-36 166 -112 -24 310 128.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='0' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.2' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={le}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(88 89 -190 187 111 220.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.4' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={be}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(9 130 -276 20 215 284)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={me}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-198 -104 327 -623 400 399.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='.5' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<clipPath id={clip}>
|
||||
<path d='M.2.2h512v512H.2z' />
|
||||
</clipPath>
|
||||
<g clipPath={`url(#${clip})`}>
|
||||
<path
|
||||
d='M382.3 475.6c-3.1 23.4-26 41.6-48.7 35.3-32.4-8.9-69.9-22.8-103.6-25.4l-51.7-4a34 34 0 0 1-22-10.2l-89-91.7a34 34 0 0 1-6.7-37.7s55-121 57.1-127.3c2-6.3 9.6-61.2 14-90.6 1.2-7.9 5-15 11-20.3L248 8.9a34.1 34.1 0 0 1 49.6 4.3L386 125.6a37 37 0 0 1 7.6 22.4c0 21.3 1.8 65 13.6 93.2 11.5 27.3 32.5 57 43.5 71.5a17.3 17.3 0 0 1 1.3 19.2 1494 1494 0 0 1-44.8 70.6c-15 22.3-21.9 49.9-25 73.1z'
|
||||
fill='#6c31e3'
|
||||
/>
|
||||
<path
|
||||
d='M165.9 478.3c41.4-84 40.2-144.2 22.6-187-16.2-39.6-46.3-64.5-70-80-.6 2.3-1.3 4.4-2.2 6.5L60.6 342a34 34 0 0 0 6.6 37.7l89.1 91.7a34 34 0 0 0 9.6 7z'
|
||||
fill={`url(#${bl})`}
|
||||
/>
|
||||
<path
|
||||
d='M278.4 307.8c11.2 1.2 22.2 3.6 32.8 7.6 34 12.7 65 41.2 90.5 96.3 1.8-3.1 3.6-6.2 5.6-9.2a1536 1536 0 0 0 44.8-70.6 17 17 0 0 0-1.3-19.2c-11-14.6-32-44.2-43.5-71.5-11.8-28.2-13.5-72-13.6-93.2 0-8.1-2.6-16-7.6-22.4L297.6 13.2a34 34 0 0 0-1.5-1.7 96 96 0 0 1 2 54 198.3 198.3 0 0 1-17.6 41.3l-7.2 14.2a171 171 0 0 0-19.4 71c-1.2 29.4 4.8 66.4 24.5 115.8z'
|
||||
fill={`url(#${tr})`}
|
||||
/>
|
||||
<path
|
||||
d='M278.4 307.8c-19.7-49.4-25.8-86.4-24.5-115.9a171 171 0 0 1 19.4-71c2.3-4.8 4.8-9.5 7.2-14.1 7.1-13.9 14-27 17.6-41.4a96 96 0 0 0-2-54A34.1 34.1 0 0 0 248 9l-105.4 94.8a34.1 34.1 0 0 0-10.9 20.3l-12.8 85-.5 2.3c23.8 15.5 54 40.4 70.1 80a147 147 0 0 1 7.8 24.8c28-6.8 55.7-11 82.1-8.3z'
|
||||
fill={`url(#${tl})`}
|
||||
/>
|
||||
<path
|
||||
d='M333.6 511c22.7 6.2 45.6-12 48.7-35.4a187 187 0 0 1 19.4-63.9c-25.6-55-56.5-83.6-90.4-96.3-36-13.4-75.2-9-115 .7 8.9 40.4 3.6 93.3-30.4 162.2 4 1.8 8.1 3 12.5 3.3 0 0 24.4 2 53.6 4.1 29 2 72.4 17.1 101.6 25.2z'
|
||||
fill={`url(#${br})`}
|
||||
/>
|
||||
<g clipRule='evenodd' fillRule='evenodd'>
|
||||
<path
|
||||
d='M254.1 190c-1.3 29.2 2.4 62.8 22.1 112.1l-6.2-.5c-17.7-51.5-21.5-78-20.2-107.6a174.7 174.7 0 0 1 20.4-72c2.4-4.9 8-14.1 10.5-18.8 7.1-13.7 11.9-21 16-33.6 5.7-17.5 4.5-25.9 3.8-34.1 4.6 29.9-12.7 56-25.7 82.4a177.1 177.1 0 0 0-20.7 72z'
|
||||
fill={`url(#${te})`}
|
||||
/>
|
||||
<path
|
||||
d='M194.3 293.4c2.4 5.4 4.6 9.8 6 16.5L195 311c-2.1-7.8-3.8-13.4-6.8-20-17.8-42-46.3-63.6-69.7-79.5 28.2 15.2 57.2 39 75.7 81.9z'
|
||||
fill={`url(#${le})`}
|
||||
/>
|
||||
<path
|
||||
d='M200.6 315.1c9.8 46-1.2 104.2-33.6 160.9 27.1-56.2 40.2-110.1 29.3-160z'
|
||||
fill={`url(#${be})`}
|
||||
/>
|
||||
<path
|
||||
d='M312.5 311c53.1 19.9 73.6 63.6 88.9 100-19-38.1-45.2-80.3-90.8-96-34.8-11.8-64.1-10.4-114.3 1l-1.1-5c53.2-12.1 81-13.5 117.3 0z'
|
||||
fill={`url(#${me})`}
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function NotionIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' width='1em' height='1em' {...props}>
|
||||
|
||||
@@ -103,6 +103,7 @@ import {
|
||||
MySQLIcon,
|
||||
Neo4jIcon,
|
||||
NotionIcon,
|
||||
ObsidianIcon,
|
||||
OnePasswordIcon,
|
||||
OpenAIIcon,
|
||||
OutlookIcon,
|
||||
@@ -265,6 +266,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
||||
mysql: MySQLIcon,
|
||||
neo4j: Neo4jIcon,
|
||||
notion_v2: NotionIcon,
|
||||
obsidian: ObsidianIcon,
|
||||
onedrive: MicrosoftOneDriveIcon,
|
||||
onepassword: OnePasswordIcon,
|
||||
openai: OpenAIIcon,
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
"mysql",
|
||||
"neo4j",
|
||||
"notion",
|
||||
"obsidian",
|
||||
"onedrive",
|
||||
"onepassword",
|
||||
"openai",
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
---
|
||||
title: Obsidian
|
||||
description: Interact with your Obsidian vault via the Local REST API
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
|
||||
<BlockInfoCard
|
||||
type="obsidian"
|
||||
color="#0F0F0F"
|
||||
/>
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Read, create, update, search, and delete notes in your Obsidian vault. Manage periodic notes, execute commands, and patch content at specific locations. Requires the Obsidian Local REST API plugin.
|
||||
|
||||
|
||||
|
||||
## Tools
|
||||
|
||||
### `obsidian_append_active`
|
||||
|
||||
Append content to the currently active file in Obsidian
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `content` | string | Yes | Markdown content to append to the active file |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `appended` | boolean | Whether content was successfully appended |
|
||||
|
||||
### `obsidian_append_note`
|
||||
|
||||
Append content to an existing note in your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path to the note relative to vault root \(e.g. "folder/note.md"\) |
|
||||
| `content` | string | Yes | Markdown content to append to the note |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `filename` | string | Path of the note |
|
||||
| `appended` | boolean | Whether content was successfully appended |
|
||||
|
||||
### `obsidian_append_periodic_note`
|
||||
|
||||
Append content to the current periodic note (daily, weekly, monthly, quarterly, or yearly). Creates the note if it does not exist.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `period` | string | Yes | Period type: daily, weekly, monthly, quarterly, or yearly |
|
||||
| `content` | string | Yes | Markdown content to append to the periodic note |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `period` | string | Period type of the note |
|
||||
| `appended` | boolean | Whether content was successfully appended |
|
||||
|
||||
### `obsidian_create_note`
|
||||
|
||||
Create or replace a note in your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path for the note relative to vault root \(e.g. "folder/note.md"\) |
|
||||
| `content` | string | Yes | Markdown content for the note |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `filename` | string | Path of the created note |
|
||||
| `created` | boolean | Whether the note was successfully created |
|
||||
|
||||
### `obsidian_delete_note`
|
||||
|
||||
Delete a note from your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path to the note to delete relative to vault root |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `filename` | string | Path of the deleted note |
|
||||
| `deleted` | boolean | Whether the note was successfully deleted |
|
||||
|
||||
### `obsidian_execute_command`
|
||||
|
||||
Execute a command in Obsidian (e.g. open daily note, toggle sidebar)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `commandId` | string | Yes | ID of the command to execute \(use List Commands operation to discover available commands\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `commandId` | string | ID of the executed command |
|
||||
| `executed` | boolean | Whether the command was successfully executed |
|
||||
|
||||
### `obsidian_get_active`
|
||||
|
||||
Retrieve the content of the currently active file in Obsidian
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `content` | string | Markdown content of the active file |
|
||||
| `filename` | string | Path to the active file |
|
||||
|
||||
### `obsidian_get_note`
|
||||
|
||||
Retrieve the content of a note from your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path to the note relative to vault root \(e.g. "folder/note.md"\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `content` | string | Markdown content of the note |
|
||||
| `filename` | string | Path to the note |
|
||||
|
||||
### `obsidian_get_periodic_note`
|
||||
|
||||
Retrieve the current periodic note (daily, weekly, monthly, quarterly, or yearly)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `period` | string | Yes | Period type: daily, weekly, monthly, quarterly, or yearly |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `content` | string | Markdown content of the periodic note |
|
||||
| `period` | string | Period type of the note |
|
||||
|
||||
### `obsidian_list_commands`
|
||||
|
||||
List all available commands in Obsidian
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `commands` | json | List of available commands with IDs and names |
|
||||
| ↳ `id` | string | Command identifier |
|
||||
| ↳ `name` | string | Human-readable command name |
|
||||
|
||||
### `obsidian_list_files`
|
||||
|
||||
List files and directories in your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `path` | string | No | Directory path relative to vault root. Leave empty to list root. |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `files` | json | List of files and directories |
|
||||
| ↳ `path` | string | File or directory path |
|
||||
| ↳ `type` | string | Whether the entry is a file or directory |
|
||||
|
||||
### `obsidian_open_file`
|
||||
|
||||
Open a file in the Obsidian UI (creates the file if it does not exist)
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path to the file relative to vault root |
|
||||
| `newLeaf` | boolean | No | Whether to open the file in a new leaf/tab |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `filename` | string | Path of the opened file |
|
||||
| `opened` | boolean | Whether the file was successfully opened |
|
||||
|
||||
### `obsidian_patch_active`
|
||||
|
||||
Insert or replace content at a specific heading, block reference, or frontmatter field in the active file
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `content` | string | Yes | Content to insert at the target location |
|
||||
| `operation` | string | Yes | How to insert content: append, prepend, or replace |
|
||||
| `targetType` | string | Yes | Type of target: heading, block, or frontmatter |
|
||||
| `target` | string | Yes | Target identifier \(heading text, block reference ID, or frontmatter field name\) |
|
||||
| `targetDelimiter` | string | No | Delimiter for nested headings \(default: "::"\) |
|
||||
| `trimTargetWhitespace` | boolean | No | Whether to trim whitespace from target before matching \(default: false\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `patched` | boolean | Whether the active file was successfully patched |
|
||||
|
||||
### `obsidian_patch_note`
|
||||
|
||||
Insert or replace content at a specific heading, block reference, or frontmatter field in a note
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `filename` | string | Yes | Path to the note relative to vault root \(e.g. "folder/note.md"\) |
|
||||
| `content` | string | Yes | Content to insert at the target location |
|
||||
| `operation` | string | Yes | How to insert content: append, prepend, or replace |
|
||||
| `targetType` | string | Yes | Type of target: heading, block, or frontmatter |
|
||||
| `target` | string | Yes | Target identifier \(heading text, block reference ID, or frontmatter field name\) |
|
||||
| `targetDelimiter` | string | No | Delimiter for nested headings \(default: "::"\) |
|
||||
| `trimTargetWhitespace` | boolean | No | Whether to trim whitespace from target before matching \(default: false\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `filename` | string | Path of the patched note |
|
||||
| `patched` | boolean | Whether the note was successfully patched |
|
||||
|
||||
### `obsidian_search`
|
||||
|
||||
Search for text across notes in your Obsidian vault
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key from Obsidian Local REST API plugin settings |
|
||||
| `baseUrl` | string | Yes | Base URL for the Obsidian Local REST API |
|
||||
| `query` | string | Yes | Text to search for across vault notes |
|
||||
| `contextLength` | number | No | Number of characters of context around each match \(default: 100\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `results` | json | Search results with filenames, scores, and matching contexts |
|
||||
| ↳ `filename` | string | Path to the matching note |
|
||||
| ↳ `score` | number | Relevance score |
|
||||
| ↳ `matches` | json | Matching text contexts |
|
||||
| ↳ `context` | string | Text surrounding the match |
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
import { ObsidianIcon } from '@/components/icons'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
import { AuthMode } from '@/blocks/types'
|
||||
|
||||
export const ObsidianBlock: BlockConfig = {
|
||||
type: 'obsidian',
|
||||
name: 'Obsidian',
|
||||
description: 'Interact with your Obsidian vault via the Local REST API',
|
||||
longDescription:
|
||||
'Read, create, update, search, and delete notes in your Obsidian vault. Manage periodic notes, execute commands, and patch content at specific locations. Requires the Obsidian Local REST API plugin.',
|
||||
docsLink: 'https://docs.sim.ai/tools/obsidian',
|
||||
category: 'tools',
|
||||
bgColor: '#0F0F0F',
|
||||
icon: ObsidianIcon,
|
||||
authMode: AuthMode.ApiKey,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'List Files', id: 'list_files' },
|
||||
{ label: 'Get Note', id: 'get_note' },
|
||||
{ label: 'Create Note', id: 'create_note' },
|
||||
{ label: 'Append to Note', id: 'append_note' },
|
||||
{ label: 'Patch Note', id: 'patch_note' },
|
||||
{ label: 'Delete Note', id: 'delete_note' },
|
||||
{ label: 'Search', id: 'search' },
|
||||
{ label: 'Get Active File', id: 'get_active' },
|
||||
{ label: 'Append to Active File', id: 'append_active' },
|
||||
{ label: 'Patch Active File', id: 'patch_active' },
|
||||
{ label: 'Open File', id: 'open_file' },
|
||||
{ label: 'List Commands', id: 'list_commands' },
|
||||
{ label: 'Execute Command', id: 'execute_command' },
|
||||
{ label: 'Get Periodic Note', id: 'get_periodic_note' },
|
||||
{ label: 'Append to Periodic Note', id: 'append_periodic_note' },
|
||||
],
|
||||
value: () => 'get_note',
|
||||
},
|
||||
{
|
||||
id: 'baseUrl',
|
||||
title: 'Base URL',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://127.0.0.1:27124',
|
||||
value: () => 'https://127.0.0.1:27124',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Obsidian Local REST API key',
|
||||
password: true,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'path',
|
||||
title: 'Directory Path',
|
||||
type: 'short-input',
|
||||
placeholder: 'Leave empty for vault root (e.g. "Projects/notes")',
|
||||
condition: { field: 'operation', value: 'list_files' },
|
||||
},
|
||||
{
|
||||
id: 'filename',
|
||||
title: 'Note Path',
|
||||
type: 'short-input',
|
||||
placeholder: 'folder/note.md',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_note', 'create_note', 'append_note', 'patch_note', 'delete_note', 'open_file'],
|
||||
},
|
||||
required: {
|
||||
field: 'operation',
|
||||
value: ['get_note', 'create_note', 'append_note', 'patch_note', 'delete_note', 'open_file'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: 'Content',
|
||||
type: 'long-input',
|
||||
placeholder: 'Markdown content',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'create_note',
|
||||
'append_note',
|
||||
'patch_note',
|
||||
'append_active',
|
||||
'patch_active',
|
||||
'append_periodic_note',
|
||||
],
|
||||
},
|
||||
required: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'create_note',
|
||||
'append_note',
|
||||
'patch_note',
|
||||
'append_active',
|
||||
'patch_active',
|
||||
'append_periodic_note',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'patchOperation',
|
||||
title: 'Patch Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Append', id: 'append' },
|
||||
{ label: 'Prepend', id: 'prepend' },
|
||||
{ label: 'Replace', id: 'replace' },
|
||||
],
|
||||
value: () => 'append',
|
||||
condition: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
required: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
},
|
||||
{
|
||||
id: 'targetType',
|
||||
title: 'Target Type',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Heading', id: 'heading' },
|
||||
{ label: 'Block Reference', id: 'block' },
|
||||
{ label: 'Frontmatter', id: 'frontmatter' },
|
||||
],
|
||||
value: () => 'heading',
|
||||
condition: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
required: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
},
|
||||
{
|
||||
id: 'target',
|
||||
title: 'Target',
|
||||
type: 'short-input',
|
||||
placeholder: 'Heading text, block ID, or frontmatter field',
|
||||
condition: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
required: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
},
|
||||
{
|
||||
id: 'targetDelimiter',
|
||||
title: 'Target Delimiter',
|
||||
type: 'short-input',
|
||||
placeholder: ':: (default)',
|
||||
condition: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'trimTargetWhitespace',
|
||||
title: 'Trim Target Whitespace',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: ['patch_note', 'patch_active'] },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'query',
|
||||
title: 'Search Query',
|
||||
type: 'short-input',
|
||||
placeholder: 'Text to search for',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
required: { field: 'operation', value: 'search' },
|
||||
},
|
||||
{
|
||||
id: 'contextLength',
|
||||
title: 'Context Length',
|
||||
type: 'short-input',
|
||||
placeholder: '100',
|
||||
condition: { field: 'operation', value: 'search' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'commandId',
|
||||
title: 'Command ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'e.g. daily-notes:open-today',
|
||||
condition: { field: 'operation', value: 'execute_command' },
|
||||
required: { field: 'operation', value: 'execute_command' },
|
||||
},
|
||||
{
|
||||
id: 'newLeaf',
|
||||
title: 'Open in New Tab',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'open_file' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'period',
|
||||
title: 'Period',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Daily', id: 'daily' },
|
||||
{ label: 'Weekly', id: 'weekly' },
|
||||
{ label: 'Monthly', id: 'monthly' },
|
||||
{ label: 'Quarterly', id: 'quarterly' },
|
||||
{ label: 'Yearly', id: 'yearly' },
|
||||
],
|
||||
value: () => 'daily',
|
||||
condition: { field: 'operation', value: ['get_periodic_note', 'append_periodic_note'] },
|
||||
required: { field: 'operation', value: ['get_periodic_note', 'append_periodic_note'] },
|
||||
},
|
||||
],
|
||||
|
||||
tools: {
|
||||
access: [
|
||||
'obsidian_append_active',
|
||||
'obsidian_append_note',
|
||||
'obsidian_append_periodic_note',
|
||||
'obsidian_create_note',
|
||||
'obsidian_delete_note',
|
||||
'obsidian_execute_command',
|
||||
'obsidian_get_active',
|
||||
'obsidian_get_note',
|
||||
'obsidian_get_periodic_note',
|
||||
'obsidian_list_commands',
|
||||
'obsidian_list_files',
|
||||
'obsidian_open_file',
|
||||
'obsidian_patch_active',
|
||||
'obsidian_patch_note',
|
||||
'obsidian_search',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => `obsidian_${params.operation}`,
|
||||
params: (params) => {
|
||||
const result: Record<string, unknown> = {}
|
||||
if (params.contextLength) {
|
||||
result.contextLength = Number(params.contextLength)
|
||||
}
|
||||
if (params.patchOperation) {
|
||||
result.operation = params.patchOperation
|
||||
}
|
||||
return result
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
inputs: {
|
||||
operation: { type: 'string', description: 'Operation to perform' },
|
||||
baseUrl: { type: 'string', description: 'Base URL for the Obsidian Local REST API' },
|
||||
apiKey: { type: 'string', description: 'API key for authentication' },
|
||||
filename: { type: 'string', description: 'Path to the note relative to vault root' },
|
||||
content: { type: 'string', description: 'Markdown content for the note' },
|
||||
path: { type: 'string', description: 'Directory path to list' },
|
||||
query: { type: 'string', description: 'Text to search for' },
|
||||
contextLength: { type: 'number', description: 'Characters of context around matches' },
|
||||
commandId: { type: 'string', description: 'ID of the command to execute' },
|
||||
patchOperation: { type: 'string', description: 'Patch operation: append, prepend, or replace' },
|
||||
targetType: { type: 'string', description: 'Target type: heading, block, or frontmatter' },
|
||||
target: { type: 'string', description: 'Target identifier for patch operations' },
|
||||
targetDelimiter: { type: 'string', description: 'Delimiter for nested headings' },
|
||||
trimTargetWhitespace: { type: 'boolean', description: 'Trim whitespace from target' },
|
||||
newLeaf: { type: 'boolean', description: 'Open file in new tab' },
|
||||
period: { type: 'string', description: 'Periodic note period type' },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Markdown content of the note' },
|
||||
filename: { type: 'string', description: 'Path to the note' },
|
||||
files: { type: 'json', description: 'List of files and directories (path, type)' },
|
||||
results: { type: 'json', description: 'Search results (filename, score, matches)' },
|
||||
commands: { type: 'json', description: 'List of available commands (id, name)' },
|
||||
created: { type: 'boolean', description: 'Whether the note was created' },
|
||||
appended: { type: 'boolean', description: 'Whether content was appended' },
|
||||
patched: { type: 'boolean', description: 'Whether content was patched' },
|
||||
deleted: { type: 'boolean', description: 'Whether the note was deleted' },
|
||||
executed: { type: 'boolean', description: 'Whether the command was executed' },
|
||||
opened: { type: 'boolean', description: 'Whether the file was opened' },
|
||||
commandId: { type: 'string', description: 'ID of the executed command' },
|
||||
period: { type: 'string', description: 'Period type of the periodic note' },
|
||||
},
|
||||
}
|
||||
@@ -113,6 +113,7 @@ import { MySQLBlock } from '@/blocks/blocks/mysql'
|
||||
import { Neo4jBlock } from '@/blocks/blocks/neo4j'
|
||||
import { NoteBlock } from '@/blocks/blocks/note'
|
||||
import { NotionBlock, NotionV2Block } from '@/blocks/blocks/notion'
|
||||
import { ObsidianBlock } from '@/blocks/blocks/obsidian'
|
||||
import { OneDriveBlock } from '@/blocks/blocks/onedrive'
|
||||
import { OnePasswordBlock } from '@/blocks/blocks/onepassword'
|
||||
import { OpenAIBlock } from '@/blocks/blocks/openai'
|
||||
@@ -320,6 +321,7 @@ export const registry: Record<string, BlockConfig> = {
|
||||
note: NoteBlock,
|
||||
notion: NotionBlock,
|
||||
notion_v2: NotionV2Block,
|
||||
obsidian: ObsidianBlock,
|
||||
onepassword: OnePasswordBlock,
|
||||
onedrive: OneDriveBlock,
|
||||
openai: OpenAIBlock,
|
||||
|
||||
@@ -710,6 +710,155 @@ export function PerplexityIcon(props: SVGProps<SVGSVGElement>) {
|
||||
)
|
||||
}
|
||||
|
||||
export function ObsidianIcon(props: SVGProps<SVGSVGElement>) {
|
||||
const id = useId()
|
||||
const bl = `${id}-bl`
|
||||
const tr = `${id}-tr`
|
||||
const tl = `${id}-tl`
|
||||
const br = `${id}-br`
|
||||
const te = `${id}-te`
|
||||
const le = `${id}-le`
|
||||
const be = `${id}-be`
|
||||
const me = `${id}-me`
|
||||
const clip = `${id}-clip`
|
||||
return (
|
||||
<svg {...props} viewBox='0 0 512 512' fill='none' xmlns='http://www.w3.org/2000/svg'>
|
||||
<radialGradient
|
||||
id={bl}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-59 -225 150 -39 161.4 470)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.4' />
|
||||
<stop offset='1' stopOpacity='.1' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={tr}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(50 -379 280 37 360 374.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.6' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.1' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={tl}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(69 -319 218 47 175.4 307)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.8' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.4' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={br}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-96 -163 187 -111 335.3 512.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.3' />
|
||||
<stop offset='1' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={te}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-36 166 -112 -24 310 128.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='0' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.2' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={le}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(88 89 -190 187 111 220.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.4' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={be}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(9 130 -276 20 215 284)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id={me}
|
||||
cx='0'
|
||||
cy='0'
|
||||
gradientTransform='matrix(-198 -104 327 -623 400 399.2)'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
r='1'
|
||||
>
|
||||
<stop offset='0' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='.5' stopColor='#fff' stopOpacity='.2' />
|
||||
<stop offset='1' stopColor='#fff' stopOpacity='.3' />
|
||||
</radialGradient>
|
||||
<clipPath id={clip}>
|
||||
<path d='M.2.2h512v512H.2z' />
|
||||
</clipPath>
|
||||
<g clipPath={`url(#${clip})`}>
|
||||
<path
|
||||
d='M382.3 475.6c-3.1 23.4-26 41.6-48.7 35.3-32.4-8.9-69.9-22.8-103.6-25.4l-51.7-4a34 34 0 0 1-22-10.2l-89-91.7a34 34 0 0 1-6.7-37.7s55-121 57.1-127.3c2-6.3 9.6-61.2 14-90.6 1.2-7.9 5-15 11-20.3L248 8.9a34.1 34.1 0 0 1 49.6 4.3L386 125.6a37 37 0 0 1 7.6 22.4c0 21.3 1.8 65 13.6 93.2 11.5 27.3 32.5 57 43.5 71.5a17.3 17.3 0 0 1 1.3 19.2 1494 1494 0 0 1-44.8 70.6c-15 22.3-21.9 49.9-25 73.1z'
|
||||
fill='#6c31e3'
|
||||
/>
|
||||
<path
|
||||
d='M165.9 478.3c41.4-84 40.2-144.2 22.6-187-16.2-39.6-46.3-64.5-70-80-.6 2.3-1.3 4.4-2.2 6.5L60.6 342a34 34 0 0 0 6.6 37.7l89.1 91.7a34 34 0 0 0 9.6 7z'
|
||||
fill={`url(#${bl})`}
|
||||
/>
|
||||
<path
|
||||
d='M278.4 307.8c11.2 1.2 22.2 3.6 32.8 7.6 34 12.7 65 41.2 90.5 96.3 1.8-3.1 3.6-6.2 5.6-9.2a1536 1536 0 0 0 44.8-70.6 17 17 0 0 0-1.3-19.2c-11-14.6-32-44.2-43.5-71.5-11.8-28.2-13.5-72-13.6-93.2 0-8.1-2.6-16-7.6-22.4L297.6 13.2a34 34 0 0 0-1.5-1.7 96 96 0 0 1 2 54 198.3 198.3 0 0 1-17.6 41.3l-7.2 14.2a171 171 0 0 0-19.4 71c-1.2 29.4 4.8 66.4 24.5 115.8z'
|
||||
fill={`url(#${tr})`}
|
||||
/>
|
||||
<path
|
||||
d='M278.4 307.8c-19.7-49.4-25.8-86.4-24.5-115.9a171 171 0 0 1 19.4-71c2.3-4.8 4.8-9.5 7.2-14.1 7.1-13.9 14-27 17.6-41.4a96 96 0 0 0-2-54A34.1 34.1 0 0 0 248 9l-105.4 94.8a34.1 34.1 0 0 0-10.9 20.3l-12.8 85-.5 2.3c23.8 15.5 54 40.4 70.1 80a147 147 0 0 1 7.8 24.8c28-6.8 55.7-11 82.1-8.3z'
|
||||
fill={`url(#${tl})`}
|
||||
/>
|
||||
<path
|
||||
d='M333.6 511c22.7 6.2 45.6-12 48.7-35.4a187 187 0 0 1 19.4-63.9c-25.6-55-56.5-83.6-90.4-96.3-36-13.4-75.2-9-115 .7 8.9 40.4 3.6 93.3-30.4 162.2 4 1.8 8.1 3 12.5 3.3 0 0 24.4 2 53.6 4.1 29 2 72.4 17.1 101.6 25.2z'
|
||||
fill={`url(#${br})`}
|
||||
/>
|
||||
<g clipRule='evenodd' fillRule='evenodd'>
|
||||
<path
|
||||
d='M254.1 190c-1.3 29.2 2.4 62.8 22.1 112.1l-6.2-.5c-17.7-51.5-21.5-78-20.2-107.6a174.7 174.7 0 0 1 20.4-72c2.4-4.9 8-14.1 10.5-18.8 7.1-13.7 11.9-21 16-33.6 5.7-17.5 4.5-25.9 3.8-34.1 4.6 29.9-12.7 56-25.7 82.4a177.1 177.1 0 0 0-20.7 72z'
|
||||
fill={`url(#${te})`}
|
||||
/>
|
||||
<path
|
||||
d='M194.3 293.4c2.4 5.4 4.6 9.8 6 16.5L195 311c-2.1-7.8-3.8-13.4-6.8-20-17.8-42-46.3-63.6-69.7-79.5 28.2 15.2 57.2 39 75.7 81.9z'
|
||||
fill={`url(#${le})`}
|
||||
/>
|
||||
<path
|
||||
d='M200.6 315.1c9.8 46-1.2 104.2-33.6 160.9 27.1-56.2 40.2-110.1 29.3-160z'
|
||||
fill={`url(#${be})`}
|
||||
/>
|
||||
<path
|
||||
d='M312.5 311c53.1 19.9 73.6 63.6 88.9 100-19-38.1-45.2-80.3-90.8-96-34.8-11.8-64.1-10.4-114.3 1l-1.1-5c53.2-12.1 81-13.5 117.3 0z'
|
||||
fill={`url(#${me})`}
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function NotionIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' width='1em' height='1em' {...props}>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianAppendActiveParams, ObsidianAppendActiveResponse } from './types'
|
||||
|
||||
export const appendActiveTool: ToolConfig<
|
||||
ObsidianAppendActiveParams,
|
||||
ObsidianAppendActiveResponse
|
||||
> = {
|
||||
id: 'obsidian_append_active',
|
||||
name: 'Obsidian Append to Active File',
|
||||
description: 'Append content to the currently active file in Obsidian',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Markdown content to append to the active file',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/active/`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
}),
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to append to active file: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
appended: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
appended: {
|
||||
type: 'boolean',
|
||||
description: 'Whether content was successfully appended',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianAppendNoteParams, ObsidianAppendNoteResponse } from './types'
|
||||
|
||||
export const appendNoteTool: ToolConfig<ObsidianAppendNoteParams, ObsidianAppendNoteResponse> = {
|
||||
id: 'obsidian_append_note',
|
||||
name: 'Obsidian Append to Note',
|
||||
description: 'Append content to an existing note in your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path to the note relative to vault root (e.g. "folder/note.md")',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Markdown content to append to the note',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/vault/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
}),
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to append to note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
filename: params?.filename ?? '',
|
||||
appended: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path of the note',
|
||||
},
|
||||
appended: {
|
||||
type: 'boolean',
|
||||
description: 'Whether content was successfully appended',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianAppendPeriodicNoteParams, ObsidianAppendPeriodicNoteResponse } from './types'
|
||||
|
||||
export const appendPeriodicNoteTool: ToolConfig<
|
||||
ObsidianAppendPeriodicNoteParams,
|
||||
ObsidianAppendPeriodicNoteResponse
|
||||
> = {
|
||||
id: 'obsidian_append_periodic_note',
|
||||
name: 'Obsidian Append to Periodic Note',
|
||||
description:
|
||||
'Append content to the current periodic note (daily, weekly, monthly, quarterly, or yearly). Creates the note if it does not exist.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
period: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Period type: daily, weekly, monthly, quarterly, or yearly',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Markdown content to append to the periodic note',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/periodic/${encodeURIComponent(params.period)}/`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
}),
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to append to periodic note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
period: params?.period ?? '',
|
||||
appended: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
period: {
|
||||
type: 'string',
|
||||
description: 'Period type of the note',
|
||||
},
|
||||
appended: {
|
||||
type: 'boolean',
|
||||
description: 'Whether content was successfully appended',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianCreateNoteParams, ObsidianCreateNoteResponse } from './types'
|
||||
|
||||
export const createNoteTool: ToolConfig<ObsidianCreateNoteParams, ObsidianCreateNoteResponse> = {
|
||||
id: 'obsidian_create_note',
|
||||
name: 'Obsidian Create Note',
|
||||
description: 'Create or replace a note in your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path for the note relative to vault root (e.g. "folder/note.md")',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Markdown content for the note',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/vault/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}`
|
||||
},
|
||||
method: 'PUT',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
}),
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to create note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
filename: params?.filename ?? '',
|
||||
created: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path of the created note',
|
||||
},
|
||||
created: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the note was successfully created',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianDeleteNoteParams, ObsidianDeleteNoteResponse } from './types'
|
||||
|
||||
export const deleteNoteTool: ToolConfig<ObsidianDeleteNoteParams, ObsidianDeleteNoteResponse> = {
|
||||
id: 'obsidian_delete_note',
|
||||
name: 'Obsidian Delete Note',
|
||||
description: 'Delete a note from your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path to the note to delete relative to vault root',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/vault/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}`
|
||||
},
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to delete note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
filename: params?.filename ?? '',
|
||||
deleted: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path of the deleted note',
|
||||
},
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the note was successfully deleted',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianExecuteCommandParams, ObsidianExecuteCommandResponse } from './types'
|
||||
|
||||
export const executeCommandTool: ToolConfig<
|
||||
ObsidianExecuteCommandParams,
|
||||
ObsidianExecuteCommandResponse
|
||||
> = {
|
||||
id: 'obsidian_execute_command',
|
||||
name: 'Obsidian Execute Command',
|
||||
description: 'Execute a command in Obsidian (e.g. open daily note, toggle sidebar)',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
commandId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'ID of the command to execute (use List Commands operation to discover available commands)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/commands/${encodeURIComponent(params.commandId.trim())}/`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to execute command: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
commandId: params?.commandId ?? '',
|
||||
executed: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
commandId: {
|
||||
type: 'string',
|
||||
description: 'ID of the executed command',
|
||||
},
|
||||
executed: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the command was successfully executed',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianGetActiveParams, ObsidianGetActiveResponse } from './types'
|
||||
|
||||
export const getActiveTool: ToolConfig<ObsidianGetActiveParams, ObsidianGetActiveResponse> = {
|
||||
id: 'obsidian_get_active',
|
||||
name: 'Obsidian Get Active File',
|
||||
description: 'Retrieve the content of the currently active file in Obsidian',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/active/`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'application/vnd.olrapi.note+json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: data.content ?? '',
|
||||
filename: data.path ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: {
|
||||
type: 'string',
|
||||
description: 'Markdown content of the active file',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path to the active file',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianGetNoteParams, ObsidianGetNoteResponse } from './types'
|
||||
|
||||
export const getNoteTool: ToolConfig<ObsidianGetNoteParams, ObsidianGetNoteResponse> = {
|
||||
id: 'obsidian_get_note',
|
||||
name: 'Obsidian Get Note',
|
||||
description: 'Retrieve the content of a note from your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path to the note relative to vault root (e.g. "folder/note.md")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/vault/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'text/markdown',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to get note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
const content = await response.text()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
filename: params?.filename ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: {
|
||||
type: 'string',
|
||||
description: 'Markdown content of the note',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path to the note',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianGetPeriodicNoteParams, ObsidianGetPeriodicNoteResponse } from './types'
|
||||
|
||||
export const getPeriodicNoteTool: ToolConfig<
|
||||
ObsidianGetPeriodicNoteParams,
|
||||
ObsidianGetPeriodicNoteResponse
|
||||
> = {
|
||||
id: 'obsidian_get_periodic_note',
|
||||
name: 'Obsidian Get Periodic Note',
|
||||
description: 'Retrieve the current periodic note (daily, weekly, monthly, quarterly, or yearly)',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
period: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Period type: daily, weekly, monthly, quarterly, or yearly',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/periodic/${encodeURIComponent(params.period)}/`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'text/markdown',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
const content = await response.text()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content,
|
||||
period: params?.period ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: {
|
||||
type: 'string',
|
||||
description: 'Markdown content of the periodic note',
|
||||
},
|
||||
period: {
|
||||
type: 'string',
|
||||
description: 'Period type of the note',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export { appendActiveTool as obsidianAppendActiveTool } from './append_active'
|
||||
export { appendNoteTool as obsidianAppendNoteTool } from './append_note'
|
||||
export { appendPeriodicNoteTool as obsidianAppendPeriodicNoteTool } from './append_periodic_note'
|
||||
export { createNoteTool as obsidianCreateNoteTool } from './create_note'
|
||||
export { deleteNoteTool as obsidianDeleteNoteTool } from './delete_note'
|
||||
export { executeCommandTool as obsidianExecuteCommandTool } from './execute_command'
|
||||
export { getActiveTool as obsidianGetActiveTool } from './get_active'
|
||||
export { getNoteTool as obsidianGetNoteTool } from './get_note'
|
||||
export { getPeriodicNoteTool as obsidianGetPeriodicNoteTool } from './get_periodic_note'
|
||||
export { listCommandsTool as obsidianListCommandsTool } from './list_commands'
|
||||
export { listFilesTool as obsidianListFilesTool } from './list_files'
|
||||
export { openFileTool as obsidianOpenFileTool } from './open_file'
|
||||
export { patchActiveTool as obsidianPatchActiveTool } from './patch_active'
|
||||
export { patchNoteTool as obsidianPatchNoteTool } from './patch_note'
|
||||
export { searchTool as obsidianSearchTool } from './search'
|
||||
export * from './types'
|
||||
@@ -0,0 +1,68 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianListCommandsParams, ObsidianListCommandsResponse } from './types'
|
||||
|
||||
export const listCommandsTool: ToolConfig<
|
||||
ObsidianListCommandsParams,
|
||||
ObsidianListCommandsResponse
|
||||
> = {
|
||||
id: 'obsidian_list_commands',
|
||||
name: 'Obsidian List Commands',
|
||||
description: 'List all available commands in Obsidian',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/commands/`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to list commands: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
commands:
|
||||
data.commands?.map((cmd: { id: string; name: string }) => ({
|
||||
id: cmd.id ?? '',
|
||||
name: cmd.name ?? '',
|
||||
})) ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
commands: {
|
||||
type: 'json',
|
||||
description: 'List of available commands with IDs and names',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Command identifier' },
|
||||
name: { type: 'string', description: 'Human-readable command name' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianListFilesParams, ObsidianListFilesResponse } from './types'
|
||||
|
||||
export const listFilesTool: ToolConfig<ObsidianListFilesParams, ObsidianListFilesResponse> = {
|
||||
id: 'obsidian_list_files',
|
||||
name: 'Obsidian List Files',
|
||||
description: 'List files and directories in your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Directory path relative to vault root. Leave empty to list root.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
const path = params.path
|
||||
? `/${params.path.trim().split('/').map(encodeURIComponent).join('/')}/`
|
||||
: '/'
|
||||
return `${base}/vault${path}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to list files: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
files:
|
||||
data.files?.map((f: string | { path: string; type: string }) => {
|
||||
if (typeof f === 'string') {
|
||||
return { path: f, type: f.endsWith('/') ? 'directory' : 'file' }
|
||||
}
|
||||
return { path: f.path ?? '', type: f.type ?? 'file' }
|
||||
}) ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
files: {
|
||||
type: 'json',
|
||||
description: 'List of files and directories',
|
||||
properties: {
|
||||
path: { type: 'string', description: 'File or directory path' },
|
||||
type: { type: 'string', description: 'Whether the entry is a file or directory' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianOpenFileParams, ObsidianOpenFileResponse } from './types'
|
||||
|
||||
export const openFileTool: ToolConfig<ObsidianOpenFileParams, ObsidianOpenFileResponse> = {
|
||||
id: 'obsidian_open_file',
|
||||
name: 'Obsidian Open File',
|
||||
description: 'Open a file in the Obsidian UI (creates the file if it does not exist)',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path to the file relative to vault root',
|
||||
},
|
||||
newLeaf: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to open the file in a new leaf/tab',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
const leafParam = params.newLeaf ? '?newLeaf=true' : ''
|
||||
return `${base}/open/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}${leafParam}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to open file: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
filename: params?.filename ?? '',
|
||||
opened: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path of the opened file',
|
||||
},
|
||||
opened: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the file was successfully opened',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianPatchActiveParams, ObsidianPatchActiveResponse } from './types'
|
||||
|
||||
export const patchActiveTool: ToolConfig<ObsidianPatchActiveParams, ObsidianPatchActiveResponse> = {
|
||||
id: 'obsidian_patch_active',
|
||||
name: 'Obsidian Patch Active File',
|
||||
description:
|
||||
'Insert or replace content at a specific heading, block reference, or frontmatter field in the active file',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Content to insert at the target location',
|
||||
},
|
||||
operation: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'How to insert content: append, prepend, or replace',
|
||||
},
|
||||
targetType: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Type of target: heading, block, or frontmatter',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Target identifier (heading text, block reference ID, or frontmatter field name)',
|
||||
},
|
||||
targetDelimiter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Delimiter for nested headings (default: "::")',
|
||||
},
|
||||
trimTargetWhitespace: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to trim whitespace from target before matching (default: false)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/active/`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params) => {
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
Operation: params.operation,
|
||||
'Target-Type': params.targetType,
|
||||
Target: encodeURIComponent(params.target),
|
||||
}
|
||||
if (params.targetDelimiter) {
|
||||
headers['Target-Delimiter'] = params.targetDelimiter
|
||||
}
|
||||
if (params.trimTargetWhitespace) {
|
||||
headers['Trim-Target-Whitespace'] = 'true'
|
||||
}
|
||||
return headers
|
||||
},
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to patch active file: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
patched: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
patched: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the active file was successfully patched',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianPatchNoteParams, ObsidianPatchNoteResponse } from './types'
|
||||
|
||||
export const patchNoteTool: ToolConfig<ObsidianPatchNoteParams, ObsidianPatchNoteResponse> = {
|
||||
id: 'obsidian_patch_note',
|
||||
name: 'Obsidian Patch Note',
|
||||
description:
|
||||
'Insert or replace content at a specific heading, block reference, or frontmatter field in a note',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
filename: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Path to the note relative to vault root (e.g. "folder/note.md")',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Content to insert at the target location',
|
||||
},
|
||||
operation: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'How to insert content: append, prepend, or replace',
|
||||
},
|
||||
targetType: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Type of target: heading, block, or frontmatter',
|
||||
},
|
||||
target: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Target identifier (heading text, block reference ID, or frontmatter field name)',
|
||||
},
|
||||
targetDelimiter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Delimiter for nested headings (default: "::")',
|
||||
},
|
||||
trimTargetWhitespace: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to trim whitespace from target before matching (default: false)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
return `${base}/vault/${params.filename.trim().split('/').map(encodeURIComponent).join('/')}`
|
||||
},
|
||||
method: 'PATCH',
|
||||
headers: (params) => {
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'text/markdown',
|
||||
Operation: params.operation,
|
||||
'Target-Type': params.targetType,
|
||||
Target: encodeURIComponent(params.target),
|
||||
}
|
||||
if (params.targetDelimiter) {
|
||||
headers['Target-Delimiter'] = params.targetDelimiter
|
||||
}
|
||||
if (params.trimTargetWhitespace) {
|
||||
headers['Trim-Target-Whitespace'] = 'true'
|
||||
}
|
||||
return headers
|
||||
},
|
||||
body: (params) => params.content,
|
||||
},
|
||||
|
||||
transformResponse: async (response, params) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Failed to patch note: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
filename: params?.filename ?? '',
|
||||
patched: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
filename: {
|
||||
type: 'string',
|
||||
description: 'Path of the patched note',
|
||||
},
|
||||
patched: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the note was successfully patched',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { ObsidianSearchParams, ObsidianSearchResponse } from './types'
|
||||
|
||||
export const searchTool: ToolConfig<ObsidianSearchParams, ObsidianSearchResponse> = {
|
||||
id: 'obsidian_search',
|
||||
name: 'Obsidian Search',
|
||||
description: 'Search for text across notes in your Obsidian vault',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'API key from Obsidian Local REST API plugin settings',
|
||||
},
|
||||
baseUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Base URL for the Obsidian Local REST API',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Text to search for across vault notes',
|
||||
},
|
||||
contextLength: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of characters of context around each match (default: 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const base = params.baseUrl.replace(/\/$/, '')
|
||||
const contextParam = params.contextLength ? `&contextLength=${params.contextLength}` : ''
|
||||
return `${base}/search/simple/?query=${encodeURIComponent(params.query)}${contextParam}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'Unknown error' }))
|
||||
throw new Error(`Search failed: ${error.message ?? response.statusText}`)
|
||||
}
|
||||
const data = await response.json()
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
results:
|
||||
data?.map(
|
||||
(item: {
|
||||
filename: string
|
||||
score: number
|
||||
matches: Array<{ match: { start: number; end: number }; context: string }>
|
||||
}) => ({
|
||||
filename: item.filename ?? '',
|
||||
score: item.score ?? 0,
|
||||
matches:
|
||||
item.matches?.map((m: { context: string }) => ({
|
||||
context: m.context ?? '',
|
||||
})) ?? [],
|
||||
})
|
||||
) ?? [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
results: {
|
||||
type: 'json',
|
||||
description: 'Search results with filenames, scores, and matching contexts',
|
||||
properties: {
|
||||
filename: { type: 'string', description: 'Path to the matching note' },
|
||||
score: { type: 'number', description: 'Relevance score' },
|
||||
matches: {
|
||||
type: 'json',
|
||||
description: 'Matching text contexts',
|
||||
properties: {
|
||||
context: { type: 'string', description: 'Text surrounding the match' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export interface ObsidianBaseParams {
|
||||
apiKey: string
|
||||
baseUrl: string
|
||||
}
|
||||
|
||||
export interface ObsidianListFilesParams extends ObsidianBaseParams {
|
||||
path?: string
|
||||
}
|
||||
|
||||
export interface ObsidianListFilesResponse extends ToolResponse {
|
||||
output: {
|
||||
files: Array<{
|
||||
path: string
|
||||
type: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianGetNoteParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
}
|
||||
|
||||
export interface ObsidianGetNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
filename: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianCreateNoteParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface ObsidianCreateNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
filename: string
|
||||
created: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianAppendNoteParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface ObsidianAppendNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
filename: string
|
||||
appended: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianPatchNoteParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
content: string
|
||||
operation: string
|
||||
targetType: string
|
||||
target: string
|
||||
targetDelimiter?: string
|
||||
trimTargetWhitespace?: boolean
|
||||
}
|
||||
|
||||
export interface ObsidianPatchNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
filename: string
|
||||
patched: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianDeleteNoteParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
}
|
||||
|
||||
export interface ObsidianDeleteNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
filename: string
|
||||
deleted: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianSearchParams extends ObsidianBaseParams {
|
||||
query: string
|
||||
contextLength?: number
|
||||
}
|
||||
|
||||
export interface ObsidianSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
results: Array<{
|
||||
filename: string
|
||||
score: number
|
||||
matches: Array<{
|
||||
context: string
|
||||
}>
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianGetActiveParams extends ObsidianBaseParams {}
|
||||
|
||||
export interface ObsidianGetActiveResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
filename: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianAppendActiveParams extends ObsidianBaseParams {
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface ObsidianAppendActiveResponse extends ToolResponse {
|
||||
output: {
|
||||
appended: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianPatchActiveParams extends ObsidianBaseParams {
|
||||
content: string
|
||||
operation: string
|
||||
targetType: string
|
||||
target: string
|
||||
targetDelimiter?: string
|
||||
trimTargetWhitespace?: boolean
|
||||
}
|
||||
|
||||
export interface ObsidianPatchActiveResponse extends ToolResponse {
|
||||
output: {
|
||||
patched: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianListCommandsParams extends ObsidianBaseParams {}
|
||||
|
||||
export interface ObsidianListCommandsResponse extends ToolResponse {
|
||||
output: {
|
||||
commands: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianExecuteCommandParams extends ObsidianBaseParams {
|
||||
commandId: string
|
||||
}
|
||||
|
||||
export interface ObsidianExecuteCommandResponse extends ToolResponse {
|
||||
output: {
|
||||
commandId: string
|
||||
executed: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianOpenFileParams extends ObsidianBaseParams {
|
||||
filename: string
|
||||
newLeaf?: boolean
|
||||
}
|
||||
|
||||
export interface ObsidianOpenFileResponse extends ToolResponse {
|
||||
output: {
|
||||
filename: string
|
||||
opened: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianGetPeriodicNoteParams extends ObsidianBaseParams {
|
||||
period: string
|
||||
}
|
||||
|
||||
export interface ObsidianGetPeriodicNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
period: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianAppendPeriodicNoteParams extends ObsidianBaseParams {
|
||||
period: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface ObsidianAppendPeriodicNoteResponse extends ToolResponse {
|
||||
output: {
|
||||
period: string
|
||||
appended: boolean
|
||||
}
|
||||
}
|
||||
@@ -1450,6 +1450,23 @@ import {
|
||||
notionWriteTool,
|
||||
notionWriteV2Tool,
|
||||
} from '@/tools/notion'
|
||||
import {
|
||||
obsidianAppendActiveTool,
|
||||
obsidianAppendNoteTool,
|
||||
obsidianAppendPeriodicNoteTool,
|
||||
obsidianCreateNoteTool,
|
||||
obsidianDeleteNoteTool,
|
||||
obsidianExecuteCommandTool,
|
||||
obsidianGetActiveTool,
|
||||
obsidianGetNoteTool,
|
||||
obsidianGetPeriodicNoteTool,
|
||||
obsidianListCommandsTool,
|
||||
obsidianListFilesTool,
|
||||
obsidianOpenFileTool,
|
||||
obsidianPatchActiveTool,
|
||||
obsidianPatchNoteTool,
|
||||
obsidianSearchTool,
|
||||
} from '@/tools/obsidian'
|
||||
import {
|
||||
onedriveCreateFolderTool,
|
||||
onedriveDeleteTool,
|
||||
@@ -2739,6 +2756,21 @@ export const tools: Record<string, ToolConfig> = {
|
||||
notion_create_database_v2: notionCreateDatabaseV2Tool,
|
||||
notion_update_page_v2: notionUpdatePageV2Tool,
|
||||
notion_add_database_row_v2: notionAddDatabaseRowTool,
|
||||
obsidian_append_active: obsidianAppendActiveTool,
|
||||
obsidian_append_note: obsidianAppendNoteTool,
|
||||
obsidian_append_periodic_note: obsidianAppendPeriodicNoteTool,
|
||||
obsidian_create_note: obsidianCreateNoteTool,
|
||||
obsidian_delete_note: obsidianDeleteNoteTool,
|
||||
obsidian_execute_command: obsidianExecuteCommandTool,
|
||||
obsidian_get_active: obsidianGetActiveTool,
|
||||
obsidian_get_note: obsidianGetNoteTool,
|
||||
obsidian_get_periodic_note: obsidianGetPeriodicNoteTool,
|
||||
obsidian_list_commands: obsidianListCommandsTool,
|
||||
obsidian_list_files: obsidianListFilesTool,
|
||||
obsidian_open_file: obsidianOpenFileTool,
|
||||
obsidian_patch_active: obsidianPatchActiveTool,
|
||||
obsidian_patch_note: obsidianPatchNoteTool,
|
||||
obsidian_search: obsidianSearchTool,
|
||||
onepassword_list_vaults: onepasswordListVaultsTool,
|
||||
onepassword_get_vault: onepasswordGetVaultTool,
|
||||
onepassword_list_items: onepasswordListItemsTool,
|
||||
|
||||
Reference in New Issue
Block a user