freddie 0.0.48 → 0.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +2 -1
- package/plugins/ansi_strip/handler.js +7 -0
- package/plugins/ansi_strip/plugin.js +2 -0
- package/plugins/approval/handler.js +13 -0
- package/plugins/approval/plugin.js +2 -0
- package/plugins/bash/handler.js +33 -0
- package/plugins/bash/plugin.js +2 -0
- package/plugins/binary_extensions/handler.js +20 -0
- package/plugins/binary_extensions/plugin.js +2 -0
- package/plugins/browser/handler.js +46 -0
- package/plugins/browser/plugin.js +2 -0
- package/plugins/budget_config/handler.js +12 -0
- package/plugins/budget_config/plugin.js +2 -0
- package/plugins/checkpoint/handler.js +27 -0
- package/plugins/checkpoint/plugin.js +2 -0
- package/plugins/clarify/handler.js +13 -0
- package/plugins/clarify/plugin.js +2 -0
- package/plugins/code_execution/handler.js +25 -0
- package/plugins/code_execution/plugin.js +2 -0
- package/plugins/core-agent-machine/plugin.js +8 -0
- package/plugins/core-cli/plugin.js +83 -0
- package/plugins/core-commands/plugin.js +7 -0
- package/plugins/core-compressor/plugin.js +15 -0
- package/plugins/core-context-engine/plugin.js +7 -0
- package/plugins/core-cron/plugin.js +7 -0
- package/plugins/core-skills/plugin.js +7 -0
- package/plugins/credential_files/handler.js +14 -0
- package/plugins/credential_files/plugin.js +2 -0
- package/plugins/cronjob/handler.js +14 -0
- package/plugins/cronjob/plugin.js +2 -0
- package/plugins/debug_helpers/handler.js +8 -0
- package/plugins/debug_helpers/plugin.js +2 -0
- package/plugins/delegate/handler.js +27 -0
- package/plugins/delegate/plugin.js +2 -0
- package/plugins/discord_tool/handler.js +12 -0
- package/plugins/discord_tool/plugin.js +2 -0
- package/plugins/edit/handler.js +29 -0
- package/plugins/edit/plugin.js +2 -0
- package/plugins/env_passthrough/handler.js +14 -0
- package/plugins/env_passthrough/plugin.js +2 -0
- package/plugins/feishu_doc/handler.js +14 -0
- package/plugins/feishu_doc/plugin.js +2 -0
- package/plugins/feishu_drive/handler.js +13 -0
- package/plugins/feishu_drive/plugin.js +2 -0
- package/plugins/file_operations/handler.js +15 -0
- package/plugins/file_operations/plugin.js +2 -0
- package/plugins/file_state/handler.js +14 -0
- package/plugins/file_state/plugin.js +2 -0
- package/plugins/file_tools/handler.js +21 -0
- package/plugins/file_tools/plugin.js +2 -0
- package/plugins/fuzzy_match/handler.js +7 -0
- package/plugins/fuzzy_match/plugin.js +2 -0
- package/plugins/gm-cc/plugin.js +28 -0
- package/plugins/grep/handler.js +49 -0
- package/plugins/grep/plugin.js +2 -0
- package/plugins/gui-agents/plugin.js +26 -0
- package/plugins/gui-batch/plugin.js +11 -0
- package/plugins/gui-chat/plugin.js +22 -0
- package/plugins/gui-config/plugin.js +12 -0
- package/plugins/gui-cron/plugin.js +13 -0
- package/plugins/gui-debug/plugin.js +24 -0
- package/plugins/gui-env/plugin.js +7 -0
- package/plugins/gui-gateway/plugin.js +9 -0
- package/plugins/gui-profiles-commands-health/plugin.js +11 -0
- package/plugins/gui-sessions/plugin.js +9 -0
- package/plugins/gui-skills/plugin.js +8 -0
- package/plugins/gui-tools/plugin.js +7 -0
- package/plugins/homeassistant_tool/handler.js +14 -0
- package/plugins/homeassistant_tool/plugin.js +2 -0
- package/plugins/image_gen/handler.js +31 -0
- package/plugins/image_gen/plugin.js +2 -0
- package/plugins/interrupt/handler.js +16 -0
- package/plugins/interrupt/plugin.js +2 -0
- package/plugins/managed_tool_gateway/handler.js +9 -0
- package/plugins/managed_tool_gateway/plugin.js +2 -0
- package/plugins/mcp_oauth/handler.js +20 -0
- package/plugins/mcp_oauth/plugin.js +2 -0
- package/plugins/mcp_oauth_manager/handler.js +18 -0
- package/plugins/mcp_oauth_manager/plugin.js +2 -0
- package/plugins/mcp_tool/handler.js +34 -0
- package/plugins/mcp_tool/plugin.js +2 -0
- package/plugins/memory/handler.js +66 -0
- package/plugins/memory/plugin.js +2 -0
- package/plugins/memory-byterover/handler.js +25 -0
- package/plugins/memory-byterover/plugin.js +2 -0
- package/plugins/memory-hindsight/handler.js +25 -0
- package/plugins/memory-hindsight/plugin.js +2 -0
- package/plugins/memory-holographic/handler.js +31 -0
- package/plugins/memory-holographic/plugin.js +2 -0
- package/plugins/memory-honcho/handler.js +25 -0
- package/plugins/memory-honcho/plugin.js +2 -0
- package/plugins/memory-mem0/handler.js +25 -0
- package/plugins/memory-mem0/plugin.js +2 -0
- package/plugins/memory-openviking/handler.js +25 -0
- package/plugins/memory-openviking/plugin.js +2 -0
- package/plugins/memory-retaindb/handler.js +25 -0
- package/plugins/memory-retaindb/plugin.js +2 -0
- package/plugins/memory-supermemory/handler.js +25 -0
- package/plugins/memory-supermemory/plugin.js +2 -0
- package/plugins/mixture_of_agents/handler.js +13 -0
- package/plugins/mixture_of_agents/plugin.js +2 -0
- package/plugins/neutts_synth/handler.js +12 -0
- package/plugins/neutts_synth/plugin.js +2 -0
- package/plugins/openrouter_client/handler.js +12 -0
- package/plugins/openrouter_client/plugin.js +2 -0
- package/plugins/osv_check/handler.js +10 -0
- package/plugins/osv_check/plugin.js +2 -0
- package/plugins/patch_parser/handler.js +40 -0
- package/plugins/patch_parser/plugin.js +2 -0
- package/plugins/path_security/handler.js +14 -0
- package/plugins/path_security/plugin.js +2 -0
- package/plugins/platform-api_server/handler.js +21 -0
- package/plugins/platform-api_server/plugin.js +2 -0
- package/plugins/platform-bluebubbles/handler.js +32 -0
- package/plugins/platform-bluebubbles/plugin.js +2 -0
- package/plugins/platform-dingtalk/handler.js +32 -0
- package/plugins/platform-dingtalk/plugin.js +2 -0
- package/plugins/platform-discord/handler.js +24 -0
- package/plugins/platform-discord/plugin.js +2 -0
- package/plugins/platform-email/handler.js +51 -0
- package/plugins/platform-email/plugin.js +2 -0
- package/plugins/platform-feishu/handler.js +32 -0
- package/plugins/platform-feishu/plugin.js +2 -0
- package/plugins/platform-feishu_comment/handler.js +12 -0
- package/plugins/platform-feishu_comment/plugin.js +2 -0
- package/plugins/platform-feishu_comment_rules/handler.js +11 -0
- package/plugins/platform-feishu_comment_rules/plugin.js +2 -0
- package/plugins/platform-homeassistant/handler.js +32 -0
- package/plugins/platform-homeassistant/plugin.js +2 -0
- package/plugins/platform-matrix/handler.js +40 -0
- package/plugins/platform-matrix/plugin.js +2 -0
- package/plugins/platform-mattermost/handler.js +29 -0
- package/plugins/platform-mattermost/plugin.js +2 -0
- package/plugins/platform-qqbot/handler.js +32 -0
- package/plugins/platform-qqbot/plugin.js +2 -0
- package/plugins/platform-signal/handler.js +33 -0
- package/plugins/platform-signal/plugin.js +2 -0
- package/plugins/platform-slack/handler.js +34 -0
- package/plugins/platform-slack/plugin.js +2 -0
- package/plugins/platform-sms/handler.js +34 -0
- package/plugins/platform-sms/plugin.js +2 -0
- package/plugins/platform-telegram/handler.js +38 -0
- package/plugins/platform-telegram/plugin.js +2 -0
- package/plugins/platform-telegram_network/handler.js +17 -0
- package/plugins/platform-telegram_network/plugin.js +2 -0
- package/plugins/platform-webhook/handler.js +19 -0
- package/plugins/platform-webhook/plugin.js +2 -0
- package/plugins/platform-wecom/handler.js +32 -0
- package/plugins/platform-wecom/plugin.js +2 -0
- package/plugins/platform-wecom_callback/handler.js +15 -0
- package/plugins/platform-wecom_callback/plugin.js +2 -0
- package/plugins/platform-wecom_crypto/handler.js +16 -0
- package/plugins/platform-wecom_crypto/plugin.js +2 -0
- package/plugins/platform-weixin/handler.js +32 -0
- package/plugins/platform-weixin/plugin.js +2 -0
- package/plugins/platform-whatsapp/handler.js +40 -0
- package/plugins/platform-whatsapp/plugin.js +2 -0
- package/plugins/platform-yuanbao/handler.js +9 -0
- package/plugins/platform-yuanbao/plugin.js +2 -0
- package/plugins/platform-yuanbao_media/handler.js +5 -0
- package/plugins/platform-yuanbao_media/plugin.js +2 -0
- package/plugins/platform-yuanbao_proto/handler.js +9 -0
- package/plugins/platform-yuanbao_proto/plugin.js +2 -0
- package/plugins/platform-yuanbao_sticker/handler.js +6 -0
- package/plugins/platform-yuanbao_sticker/plugin.js +2 -0
- package/plugins/process_registry/handler.js +15 -0
- package/plugins/process_registry/plugin.js +2 -0
- package/plugins/read/handler.js +24 -0
- package/plugins/read/plugin.js +2 -0
- package/plugins/rl_training/handler.js +12 -0
- package/plugins/rl_training/plugin.js +2 -0
- package/plugins/schema_sanitizer/handler.js +17 -0
- package/plugins/schema_sanitizer/plugin.js +2 -0
- package/plugins/send_message/handler.js +30 -0
- package/plugins/send_message/plugin.js +2 -0
- package/plugins/session_search/handler.js +21 -0
- package/plugins/session_search/plugin.js +2 -0
- package/plugins/skill_manager/handler.js +16 -0
- package/plugins/skill_manager/plugin.js +2 -0
- package/plugins/skill_usage/handler.js +18 -0
- package/plugins/skill_usage/plugin.js +2 -0
- package/plugins/skills_guard/handler.js +16 -0
- package/plugins/skills_guard/plugin.js +2 -0
- package/plugins/skills_hub/handler.js +29 -0
- package/plugins/skills_hub/plugin.js +2 -0
- package/plugins/skills_index/handler.js +12 -0
- package/plugins/skills_index/plugin.js +2 -0
- package/plugins/skills_sync/handler.js +17 -0
- package/plugins/skills_sync/plugin.js +2 -0
- package/plugins/skills_tool/handler.js +9 -0
- package/plugins/skills_tool/plugin.js +2 -0
- package/plugins/slash_confirm/handler.js +14 -0
- package/plugins/slash_confirm/plugin.js +2 -0
- package/plugins/terminal/handler.js +27 -0
- package/plugins/terminal/plugin.js +2 -0
- package/plugins/tirith_security/handler.js +23 -0
- package/plugins/tirith_security/plugin.js +2 -0
- package/plugins/todo/handler.js +52 -0
- package/plugins/todo/plugin.js +2 -0
- package/plugins/tool_backend_helpers/handler.js +24 -0
- package/plugins/tool_backend_helpers/plugin.js +2 -0
- package/plugins/tool_output_limits/handler.js +14 -0
- package/plugins/tool_output_limits/plugin.js +2 -0
- package/plugins/tool_result_storage/handler.js +18 -0
- package/plugins/tool_result_storage/plugin.js +2 -0
- package/plugins/transcription/handler.js +18 -0
- package/plugins/transcription/plugin.js +2 -0
- package/plugins/tts/handler.js +18 -0
- package/plugins/tts/plugin.js +2 -0
- package/plugins/url_safety/handler.js +14 -0
- package/plugins/url_safety/plugin.js +2 -0
- package/plugins/vision/handler.js +17 -0
- package/plugins/vision/plugin.js +2 -0
- package/plugins/voice_mode/handler.js +9 -0
- package/plugins/voice_mode/plugin.js +2 -0
- package/plugins/web_search/handler.js +35 -0
- package/plugins/web_search/plugin.js +2 -0
- package/plugins/web_tools/handler.js +17 -0
- package/plugins/web_tools/plugin.js +2 -0
- package/plugins/website_policy/handler.js +13 -0
- package/plugins/website_policy/plugin.js +2 -0
- package/plugins/write/handler.js +23 -0
- package/plugins/write/plugin.js +2 -0
- package/plugins/xai_http/handler.js +12 -0
- package/plugins/xai_http/plugin.js +2 -0
- package/plugins/yuanbao_tools/handler.js +12 -0
- package/plugins/yuanbao_tools/plugin.js +2 -0
- package/src/agent/llm_resolver.js +2 -1
- package/src/agent/pi-bridge.js +3 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class ByteroverMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'byterover'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.BYTEROVER_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.byterover.com"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["BYTEROVER_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('ByteroverMemory: BYTEROVER_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class HindsightMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'hindsight'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.HINDSIGHT_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.hindsightai.com"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["HINDSIGHT_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('HindsightMemory: HINDSIGHT_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { getFreddieHome } from '../../src/plugins/../home.js'
|
|
4
|
+
|
|
5
|
+
export class HolographicMemory {
|
|
6
|
+
constructor(opts = {}) {
|
|
7
|
+
this.name = 'holographic'
|
|
8
|
+
this.dir = opts.dir || path.join(getFreddieHome(), 'memory', 'holographic')
|
|
9
|
+
fs.mkdirSync(this.dir, { recursive: true })
|
|
10
|
+
}
|
|
11
|
+
getRequiredEnv() { return [] }
|
|
12
|
+
async syncTurn(messages) {
|
|
13
|
+
const file = path.join(this.dir, Date.now() + '.json')
|
|
14
|
+
fs.writeFileSync(file, JSON.stringify({ ts: Date.now(), messages }), 'utf8')
|
|
15
|
+
return { stored: file }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const files = fs.readdirSync(this.dir).filter(f => f.endsWith('.json')).sort().slice(-20)
|
|
19
|
+
const items = []
|
|
20
|
+
for (const f of files) {
|
|
21
|
+
try {
|
|
22
|
+
const data = JSON.parse(fs.readFileSync(path.join(this.dir, f), 'utf8'))
|
|
23
|
+
const last = data.messages?.slice(-2).map(m => m.content).join(' ') || ''
|
|
24
|
+
if (!query || last.toLowerCase().includes(String(query).toLowerCase())) items.push({ file: f, summary: last.slice(0, 200) })
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
return { items }
|
|
28
|
+
}
|
|
29
|
+
async shutdown() {}
|
|
30
|
+
async postSetup() {}
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class HonchoMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'honcho'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.HONCHO_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.honcho.dev"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["HONCHO_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('HonchoMemory: HONCHO_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class Mem0Memory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'mem0'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.MEM0_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.mem0.ai/v1"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["MEM0_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('Mem0Memory: MEM0_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class OpenvikingMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'openviking'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.OPENVIKING_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.openviking.com"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["OPENVIKING_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('OpenvikingMemory: OPENVIKING_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class RetaindbMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'retaindb'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.RETAINDB_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.retaindb.com"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["RETAINDB_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('RetaindbMemory: RETAINDB_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class SupermemoryMemory {
|
|
2
|
+
constructor(opts = {}) {
|
|
3
|
+
this.name = 'supermemory'
|
|
4
|
+
this.apiKey = opts.apiKey || process.env.SUPERMEMORY_API_KEY
|
|
5
|
+
this.base = opts.base || "https://api.supermemory.ai/v3"
|
|
6
|
+
this.userId = opts.userId || 'default'
|
|
7
|
+
}
|
|
8
|
+
getRequiredEnv() { return ["SUPERMEMORY_API_KEY"] }
|
|
9
|
+
_headers() {
|
|
10
|
+
if (!this.apiKey) throw new Error('SupermemoryMemory: SUPERMEMORY_API_KEY required')
|
|
11
|
+
return { authorization: `Bearer ${this.apiKey}`, 'content-type': 'application/json' }
|
|
12
|
+
}
|
|
13
|
+
async syncTurn(messages) {
|
|
14
|
+
const res = await fetch(`${this.base}/memories`, { method: 'POST', headers: this._headers(), body: JSON.stringify({ user_id: this.userId, messages }) })
|
|
15
|
+
return { status: res.status, ok: res.ok }
|
|
16
|
+
}
|
|
17
|
+
async prefetch(query) {
|
|
18
|
+
const url = `${this.base}/memories/search?query=${encodeURIComponent(query || '')}&user_id=${encodeURIComponent(this.userId)}`
|
|
19
|
+
const res = await fetch(url, { headers: this._headers() })
|
|
20
|
+
if (!res.ok) return { items: [], status: res.status }
|
|
21
|
+
return { items: await res.json() }
|
|
22
|
+
}
|
|
23
|
+
async shutdown() {}
|
|
24
|
+
async postSetup() {}
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { runTurn } from '../../src/agent/machine.js'
|
|
2
|
+
|
|
3
|
+
export const _tool = ({
|
|
4
|
+
name: 'mixture_of_agents',
|
|
5
|
+
toolset: 'core',
|
|
6
|
+
schema: { name: 'mixture_of_agents', description: 'Run the same prompt through N sub-agents (different models or seeds), then synthesize the results. Reduces variance.', parameters: { type: 'object', properties: { prompt: { type: 'string' }, models: { type: 'array', items: { type: 'string' } }, callLLM: {} }, required: ['prompt'] } },
|
|
7
|
+
handler: async ({ prompt, models = ['default'] }, ctx = {}) => {
|
|
8
|
+
const llm = ctx.callLLM || null
|
|
9
|
+
const runs = await Promise.all(models.map(m => runTurn({ prompt, model: m, callLLM: llm, timeoutMs: 30000 }).catch(e => ({ error: String(e.message || e) }))))
|
|
10
|
+
const synthesized = runs.map(r => r.result || r.error || '').join('\n---\n')
|
|
11
|
+
return { runs: runs.length, synthesized }
|
|
12
|
+
},
|
|
13
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const _tool = ({
|
|
2
|
+
name: 'neutts_synth',
|
|
3
|
+
toolset: 'creative',
|
|
4
|
+
schema: { name: 'neutts_synth', description: 'Local NeuTTS synth (alternate TTS backend).', parameters: { type: 'object', properties: { text: { type: 'string' }, voice: { type: 'string', default: 'default' } }, required: ['text'] } },
|
|
5
|
+
requiresEnv: ['NEUTTS_URL'],
|
|
6
|
+
checkFn: () => Boolean(process.env.NEUTTS_URL),
|
|
7
|
+
handler: async ({ text, voice = 'default' }) => {
|
|
8
|
+
if (!process.env.NEUTTS_URL) return { error: 'NEUTTS_URL required' }
|
|
9
|
+
const r = await fetch(process.env.NEUTTS_URL + '/synthesize', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ text, voice }) })
|
|
10
|
+
return { status: r.status, bytes: (await r.arrayBuffer()).byteLength }
|
|
11
|
+
},
|
|
12
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const _tool = ({
|
|
2
|
+
name: 'openrouter',
|
|
3
|
+
toolset: 'core',
|
|
4
|
+
schema: { name: 'openrouter', description: 'Chat completion via OpenRouter (any model).', parameters: { type: 'object', properties: { prompt: { type: 'string' }, model: { type: 'string', default: 'anthropic/claude-sonnet-4' } }, required: ['prompt'] } },
|
|
5
|
+
requiresEnv: ['OPENROUTER_API_KEY'],
|
|
6
|
+
checkFn: () => Boolean(process.env.OPENROUTER_API_KEY),
|
|
7
|
+
handler: async ({ prompt, model = 'anthropic/claude-sonnet-4' }) => {
|
|
8
|
+
if (!process.env.OPENROUTER_API_KEY) return { error: 'OPENROUTER_API_KEY required' }
|
|
9
|
+
const r = await fetch('https://openrouter.ai/api/v1/chat/completions', { method: 'POST', headers: { authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`, 'content-type': 'application/json' }, body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }] }) })
|
|
10
|
+
return await r.json()
|
|
11
|
+
},
|
|
12
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const _tool = ({
|
|
2
|
+
name: 'osv_check',
|
|
3
|
+
toolset: 'core',
|
|
4
|
+
schema: { name: 'osv_check', description: 'Query osv.dev for known vulnerabilities. Pass either {package, version, ecosystem} or {commit_sha, repo}.', parameters: { type: 'object', properties: { package: { type: 'string' }, version: { type: 'string' }, ecosystem: { type: 'string' }, commit_sha: { type: 'string' } } } },
|
|
5
|
+
handler: async (args) => {
|
|
6
|
+
const body = args.commit_sha ? { commit: args.commit_sha } : { package: { name: args.package, ecosystem: args.ecosystem || 'npm' }, version: args.version }
|
|
7
|
+
const r = await fetch('https://api.osv.dev/v1/query', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) })
|
|
8
|
+
return await r.json()
|
|
9
|
+
},
|
|
10
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
export function applyUnifiedDiff(diff, { cwd = process.cwd() } = {}) {
|
|
4
|
+
const lines = diff.split('\n')
|
|
5
|
+
const results = []
|
|
6
|
+
let curFile = null, curHunks = [], curHunk = null
|
|
7
|
+
const flush = () => {
|
|
8
|
+
if (!curFile) return
|
|
9
|
+
const file = path.join(cwd, curFile)
|
|
10
|
+
if (!fs.existsSync(file)) { results.push({ file: curFile, error: 'not found' }); curFile = null; curHunks = []; return }
|
|
11
|
+
let src = fs.readFileSync(file, 'utf8').split('\n')
|
|
12
|
+
for (const h of curHunks) {
|
|
13
|
+
const before = src.slice(0, h.start)
|
|
14
|
+
const after = src.slice(h.start + h.removed)
|
|
15
|
+
src = [...before, ...h.added, ...after]
|
|
16
|
+
}
|
|
17
|
+
fs.writeFileSync(file, src.join('\n'), 'utf8')
|
|
18
|
+
results.push({ file: curFile, applied: curHunks.length })
|
|
19
|
+
curFile = null; curHunks = []
|
|
20
|
+
}
|
|
21
|
+
for (const l of lines) {
|
|
22
|
+
if (l.startsWith('--- ')) { flush(); curFile = l.slice(6).trim() }
|
|
23
|
+
else if (l.startsWith('+++ ')) {}
|
|
24
|
+
else if (l.startsWith('@@ ')) {
|
|
25
|
+
const m = l.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/)
|
|
26
|
+
if (m) { curHunk = { start: Number(m[1]) - 1, removed: Number(m[2]), added: [] }; curHunks.push(curHunk) }
|
|
27
|
+
} else if (curHunk) {
|
|
28
|
+
if (l.startsWith('+')) curHunk.added.push(l.slice(1))
|
|
29
|
+
else if (l.startsWith(' ')) curHunk.added.push(l.slice(1))
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
flush()
|
|
33
|
+
return results
|
|
34
|
+
}
|
|
35
|
+
export const _tool = ({
|
|
36
|
+
name: 'patch_parser',
|
|
37
|
+
toolset: 'core',
|
|
38
|
+
schema: { name: 'patch_parser', description: 'Apply a unified diff to files in cwd. Returns per-file results.', parameters: { type: 'object', properties: { diff: { type: 'string' }, cwd: { type: 'string' } }, required: ['diff'] } },
|
|
39
|
+
handler: async ({ diff, cwd }) => ({ results: applyUnifiedDiff(diff, { cwd }) }),
|
|
40
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
const FORBIDDEN = ['/etc/passwd', '/etc/shadow', '/.ssh/', '/.aws/', 'C:\\Windows\\System32']
|
|
3
|
+
export function isPathSafe(p, { cwd = process.cwd() } = {}) {
|
|
4
|
+
const abs = path.resolve(cwd, p)
|
|
5
|
+
for (const bad of FORBIDDEN) if (abs.includes(bad)) return { safe: false, reason: 'forbidden: ' + bad }
|
|
6
|
+
if (abs.includes('..')) return { safe: false, reason: 'parent reference in resolved path' }
|
|
7
|
+
return { safe: true, abs }
|
|
8
|
+
}
|
|
9
|
+
export const _tool = ({
|
|
10
|
+
name: 'path_security',
|
|
11
|
+
toolset: 'core',
|
|
12
|
+
schema: { name: 'path_security', description: 'Check whether a path is allowed (no /etc/passwd, no .ssh/, etc).', parameters: { type: 'object', properties: { path: { type: 'string' }, cwd: { type: 'string' } }, required: ['path'] } },
|
|
13
|
+
handler: async ({ path: p, cwd }) => isPathSafe(p, { cwd }),
|
|
14
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
|
+
|
|
4
|
+
export class ApiServerAdapter extends EventEmitter {
|
|
5
|
+
constructor({ port = 0 } = {}) { super(); this.port = port; this._server = null; this._messages = [] }
|
|
6
|
+
async start() {
|
|
7
|
+
const app = express()
|
|
8
|
+
app.use(express.json())
|
|
9
|
+
app.post('/messages', (req, res) => {
|
|
10
|
+
const m = { from: req.body?.from || 'api', text: req.body?.text || '', raw: req.body }
|
|
11
|
+
this.emit('message', m)
|
|
12
|
+
res.json({ ok: true })
|
|
13
|
+
})
|
|
14
|
+
app.get('/messages', (_, res) => res.json(this._messages))
|
|
15
|
+
await new Promise(resolve => { this._server = app.listen(this.port, () => resolve()) })
|
|
16
|
+
this.port = this._server.address().port
|
|
17
|
+
}
|
|
18
|
+
async stop() { if (this._server) await new Promise(r => this._server.close(() => r())) }
|
|
19
|
+
async send(reply) { this._messages.push(reply) }
|
|
20
|
+
drain() { const out = [...this._messages]; this._messages.length = 0; return out }
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
|
+
|
|
4
|
+
export class BluebubblesAdapter extends EventEmitter {
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
super()
|
|
7
|
+
this.platform = 'bluebubbles'
|
|
8
|
+
this.token = opts.token || process.env.BLUEBUBBLES_PASSWORD
|
|
9
|
+
this.port = opts.port || 0
|
|
10
|
+
this.api = opts.api || "http://localhost:1234/api/v1/message/text"
|
|
11
|
+
this._server = null
|
|
12
|
+
}
|
|
13
|
+
getRequiredEnv() { return ["BLUEBUBBLES_PASSWORD"] }
|
|
14
|
+
async start() {
|
|
15
|
+
if (!this.token) throw new Error('BluebubblesAdapter: ' + this.getRequiredEnv().join(', ') + ' required')
|
|
16
|
+
const app = express()
|
|
17
|
+
app.use(express.json())
|
|
18
|
+
app.post('/webhook', (req, res) => {
|
|
19
|
+
const text = req.body?.text || req.body?.message?.text || req.body?.content || ''
|
|
20
|
+
const from = req.body?.from || req.body?.user_id || req.body?.sender_id || ''
|
|
21
|
+
this.emit('message', { from: String(from), text, raw: req.body })
|
|
22
|
+
res.json({ ok: true })
|
|
23
|
+
})
|
|
24
|
+
await new Promise(r => { this._server = app.listen(this.port, () => r()) })
|
|
25
|
+
this.port = this._server.address().port
|
|
26
|
+
}
|
|
27
|
+
async stop() { if (this._server) await new Promise(r => this._server.close(() => r())) }
|
|
28
|
+
async send(reply) {
|
|
29
|
+
if (!this.token) throw new Error('BluebubblesAdapter: token required')
|
|
30
|
+
return fetch(this.api, { method: 'POST', headers: { authorization: `Bearer ${this.token}`, 'content-type': 'application/json' }, body: JSON.stringify({ to: reply.to, text: reply.text }) }).then(r => r.json())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
|
+
|
|
4
|
+
export class DingtalkAdapter extends EventEmitter {
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
super()
|
|
7
|
+
this.platform = 'dingtalk'
|
|
8
|
+
this.token = opts.token || process.env.DINGTALK_ACCESS_TOKEN
|
|
9
|
+
this.port = opts.port || 0
|
|
10
|
+
this.api = opts.api || "https://oapi.dingtalk.com/robot/send"
|
|
11
|
+
this._server = null
|
|
12
|
+
}
|
|
13
|
+
getRequiredEnv() { return ["DINGTALK_ACCESS_TOKEN"] }
|
|
14
|
+
async start() {
|
|
15
|
+
if (!this.token) throw new Error('DingtalkAdapter: ' + this.getRequiredEnv().join(', ') + ' required')
|
|
16
|
+
const app = express()
|
|
17
|
+
app.use(express.json())
|
|
18
|
+
app.post('/webhook', (req, res) => {
|
|
19
|
+
const text = req.body?.text || req.body?.message?.text || req.body?.content || ''
|
|
20
|
+
const from = req.body?.from || req.body?.user_id || req.body?.sender_id || ''
|
|
21
|
+
this.emit('message', { from: String(from), text, raw: req.body })
|
|
22
|
+
res.json({ ok: true })
|
|
23
|
+
})
|
|
24
|
+
await new Promise(r => { this._server = app.listen(this.port, () => r()) })
|
|
25
|
+
this.port = this._server.address().port
|
|
26
|
+
}
|
|
27
|
+
async stop() { if (this._server) await new Promise(r => this._server.close(() => r())) }
|
|
28
|
+
async send(reply) {
|
|
29
|
+
if (!this.token) throw new Error('DingtalkAdapter: token required')
|
|
30
|
+
return fetch(this.api, { method: 'POST', headers: { authorization: `Bearer ${this.token}`, 'content-type': 'application/json' }, body: JSON.stringify({ to: reply.to, text: reply.text }) }).then(r => r.json())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events'
|
|
2
|
+
|
|
3
|
+
export class DiscordAdapter extends EventEmitter {
|
|
4
|
+
constructor(opts = {}) {
|
|
5
|
+
super()
|
|
6
|
+
this.platform = 'discord'
|
|
7
|
+
this.token = opts.token || process.env.DISCORD_BOT_TOKEN
|
|
8
|
+
this.api = opts.api || 'https://discord.com/api/v10'
|
|
9
|
+
this._ws = null
|
|
10
|
+
}
|
|
11
|
+
getRequiredEnv() { return ['DISCORD_BOT_TOKEN'] }
|
|
12
|
+
async start() {
|
|
13
|
+
if (!this.token) throw new Error('DiscordAdapter: DISCORD_BOT_TOKEN required')
|
|
14
|
+
const gw = await fetch(`${this.api}/gateway/bot`, { headers: { authorization: `Bot ${this.token}` } }).then(r => r.json())
|
|
15
|
+
if (!gw.url) throw new Error('DiscordAdapter: gateway lookup failed: ' + JSON.stringify(gw))
|
|
16
|
+
this.gatewayUrl = gw.url + '/?v=10&encoding=json'
|
|
17
|
+
}
|
|
18
|
+
async stop() { try { this._ws?.close?.() } catch {} }
|
|
19
|
+
async send(reply) {
|
|
20
|
+
if (!this.token) throw new Error('DiscordAdapter: token required')
|
|
21
|
+
const url = `${this.api}/channels/${reply.to}/messages`
|
|
22
|
+
return fetch(url, { method: 'POST', headers: { authorization: `Bot ${this.token}`, 'content-type': 'application/json' }, body: JSON.stringify({ content: reply.text }) }).then(r => r.json())
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events'
|
|
2
|
+
import net from 'node:net'
|
|
3
|
+
|
|
4
|
+
export class EmailAdapter extends EventEmitter {
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
super()
|
|
7
|
+
this.platform = 'email'
|
|
8
|
+
this.smtpHost = opts.smtpHost || process.env.SMTP_HOST
|
|
9
|
+
this.smtpPort = opts.smtpPort || Number(process.env.SMTP_PORT || 587)
|
|
10
|
+
this.smtpUser = opts.smtpUser || process.env.SMTP_USER
|
|
11
|
+
this.smtpPass = opts.smtpPass || process.env.SMTP_PASS
|
|
12
|
+
this.imapHost = opts.imapHost || process.env.IMAP_HOST
|
|
13
|
+
this._running = false
|
|
14
|
+
}
|
|
15
|
+
getRequiredEnv() { return ['SMTP_HOST', 'SMTP_USER', 'SMTP_PASS'] }
|
|
16
|
+
async start() {
|
|
17
|
+
if (!this.smtpHost || !this.smtpUser || !this.smtpPass) throw new Error('EmailAdapter: SMTP_HOST/USER/PASS required')
|
|
18
|
+
this._running = true
|
|
19
|
+
}
|
|
20
|
+
async stop() { this._running = false }
|
|
21
|
+
async send(reply) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const sock = net.createConnection(this.smtpPort, this.smtpHost)
|
|
24
|
+
const lines = []
|
|
25
|
+
const send = s => sock.write(s + '\r\n')
|
|
26
|
+
sock.on('data', d => {
|
|
27
|
+
const text = d.toString()
|
|
28
|
+
lines.push(text)
|
|
29
|
+
const code = parseInt(text.slice(0, 3), 10)
|
|
30
|
+
if (code >= 400) { sock.end(); return reject(new Error('SMTP error: ' + text)) }
|
|
31
|
+
})
|
|
32
|
+
sock.on('error', reject)
|
|
33
|
+
sock.on('connect', () => {
|
|
34
|
+
send('EHLO freddie')
|
|
35
|
+
send('AUTH LOGIN')
|
|
36
|
+
send(Buffer.from(this.smtpUser).toString('base64'))
|
|
37
|
+
send(Buffer.from(this.smtpPass).toString('base64'))
|
|
38
|
+
send('MAIL FROM:<' + this.smtpUser + '>')
|
|
39
|
+
send('RCPT TO:<' + reply.to + '>')
|
|
40
|
+
send('DATA')
|
|
41
|
+
send('Subject: ' + (reply.subject || 'freddie'))
|
|
42
|
+
send('To: ' + reply.to)
|
|
43
|
+
send('')
|
|
44
|
+
send(reply.text)
|
|
45
|
+
send('.')
|
|
46
|
+
send('QUIT')
|
|
47
|
+
setTimeout(() => { sock.end(); resolve({ ok: true, log: lines.join('') }) }, 500)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { EventEmitter } from 'node:events'
|
|
3
|
+
|
|
4
|
+
export class FeishuAdapter extends EventEmitter {
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
super()
|
|
7
|
+
this.platform = 'feishu'
|
|
8
|
+
this.token = opts.token || process.env.FEISHU_APP_TOKEN
|
|
9
|
+
this.port = opts.port || 0
|
|
10
|
+
this.api = opts.api || "https://open.feishu.cn/open-apis/im/v1/messages"
|
|
11
|
+
this._server = null
|
|
12
|
+
}
|
|
13
|
+
getRequiredEnv() { return ["FEISHU_APP_TOKEN"] }
|
|
14
|
+
async start() {
|
|
15
|
+
if (!this.token) throw new Error('FeishuAdapter: ' + this.getRequiredEnv().join(', ') + ' required')
|
|
16
|
+
const app = express()
|
|
17
|
+
app.use(express.json())
|
|
18
|
+
app.post('/webhook', (req, res) => {
|
|
19
|
+
const text = req.body?.text || req.body?.message?.text || req.body?.content || ''
|
|
20
|
+
const from = req.body?.from || req.body?.user_id || req.body?.sender_id || ''
|
|
21
|
+
this.emit('message', { from: String(from), text, raw: req.body })
|
|
22
|
+
res.json({ ok: true })
|
|
23
|
+
})
|
|
24
|
+
await new Promise(r => { this._server = app.listen(this.port, () => r()) })
|
|
25
|
+
this.port = this._server.address().port
|
|
26
|
+
}
|
|
27
|
+
async stop() { if (this._server) await new Promise(r => this._server.close(() => r())) }
|
|
28
|
+
async send(reply) {
|
|
29
|
+
if (!this.token) throw new Error('FeishuAdapter: token required')
|
|
30
|
+
return fetch(this.api, { method: 'POST', headers: { authorization: `Bearer ${this.token}`, 'content-type': 'application/json' }, body: JSON.stringify({ to: reply.to, text: reply.text }) }).then(r => r.json())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export async function listComments({ token, docToken }) {
|
|
2
|
+
const r = await fetch('https://open.feishu.cn/open-apis/comments/v1/files/' + docToken + '/comments', { headers: { authorization: 'Bearer ' + token } })
|
|
3
|
+
return await r.json()
|
|
4
|
+
}
|
|
5
|
+
export async function postComment({ token, docToken, content }) {
|
|
6
|
+
const r = await fetch('https://open.feishu.cn/open-apis/comments/v1/files/' + docToken + '/comments', { method: 'POST', headers: { authorization: 'Bearer ' + token, 'content-type': 'application/json' }, body: JSON.stringify({ comment: { content } }) })
|
|
7
|
+
return await r.json()
|
|
8
|
+
}
|
|
9
|
+
export async function resolveComment({ token, docToken, commentId }) {
|
|
10
|
+
const r = await fetch('https://open.feishu.cn/open-apis/comments/v1/files/' + docToken + '/comments/' + commentId + '/patch', { method: 'PATCH', headers: { authorization: 'Bearer ' + token, 'content-type': 'application/json' }, body: JSON.stringify({ is_solved: true }) })
|
|
11
|
+
return await r.json()
|
|
12
|
+
}
|