diff options
Diffstat (limited to 'modules/core/module-aiassist.js')
| -rw-r--r-- | modules/core/module-aiassist.js | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index 3af7f9b..5a0c389 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -66,9 +66,10 @@ buildSystemPrompt() { } } catch (e) {} return 'Current date: ' + dateStr + nvfsNote + '\n' - + 'VFS\u2192Modules\u2192AI. nvfs-index for commands. Tool\u2192Observe\u2192Answer. nvfs-resolve. Destructive cmds need confirm.\n' - + 'FS: list/read/write/delete | NVFS: nvfs-resolve | Web: search/fetch | Mod: view/edit/test/reload | Config | Skills\n' - + 'Other: floating, webdav, cron, vault, sandbox, agents, wpm, mindmap, memgraph, guardrail, wget, tar, secret-* \u2014 discoverable via help'; + + 'VFS→Modules→AI. nvfs-index for commands. Tool→Observe→Answer. nvfs-resolve. Destructive cmds need confirm.\n' + + 'FS: list/read/write/delete | NVFS: nvfs-resolve | Web: search/fetch [POST=method+body] | Mod: view/edit/test/reload | Config | Skills\n' + + 'web_fetch tool: GET for normal pages (returns title+content+word_count), POST for JSON APIs like Hyperliquid /info (pass method="POST" and body as JSON string).\n' + + 'Other: floating, webdav, cron, vault, sandbox, agents, wpm, mindmap, memgraph, guardrail, wget, tar, secret-* — discoverable via help'; } getToolDefinitions() { if (!this._toolDefs) this._toolDefs = this._buildToolDefs(); @@ -135,8 +136,17 @@ buildSystemPrompt() { type: 'function', function: { name: 'web_fetch', - description: 'Fetch & extract URL content', - parameters: { type: 'object', properties: { url: { type: 'string', description: 'Full URL' } }, required: ['url'] } + description: 'Fetch & extract URL content. Supports GET (default) and POST (for APIs like Hyperliquid /info).', + parameters: { + type: 'object', + properties: { + url: { type: 'string', description: 'Full URL' }, + method: { type: 'string', enum: ['GET', 'POST'], description: 'HTTP method (default GET)' }, + body: { type: 'string', description: 'Request body for POST (JSON string, max 10KB)' }, + content_type: { type: 'string', description: 'Content-Type header (default application/json for POST)' } + }, + required: ['url'] + } } }, { type: 'function', @@ -1466,7 +1476,10 @@ buildSystemPrompt() { if (!query) return JSON.stringify({ error: 'No query provided' }); try { const resp = await fetch('/api/search?q=' + encodeURIComponent(query)); - if (!resp.ok) { return JSON.stringify({ error: 'Search API returned HTTP ' + resp.status }); } + if (!resp.ok) { + const err = await resp.json().catch(() => ({})); + return JSON.stringify({ error: 'Search failed: ' + (err.error || `HTTP ${resp.status}`), status: resp.status, details: err.details || '' }); + } const data = await resp.json(); const results = data.results || []; if (results.length === 0) return JSON.stringify({ message: 'No results found' }); @@ -1476,12 +1489,27 @@ buildSystemPrompt() { case 'web_fetch': { const url = a.url || ''; if (!url) return JSON.stringify({ error: 'No URL provided' }); + const method = (a.method || 'GET').toUpperCase(); + const body = a.body || ''; + const contentType = a.content_type || (method === 'POST' ? 'application/json' : ''); try { - const resp = await fetch('/api/extract?url=' + encodeURIComponent(url)); + // Use /api/fetch for POST, /api/extract for GET (extract is cleaner for readable content) + const endpoint = method === 'POST' ? '/api/fetch' : '/api/extract'; + const params = new URLSearchParams({ url }); + if (method === 'POST') { params.set('method', 'POST'); params.set('body', body); if (contentType) params.set('content_type', contentType); } + const resp = await fetch(endpoint + '?' + params.toString()); if (resp.status === 403) return JSON.stringify({ error: 'URL blocked — internal network' }); - if (!resp.ok) { return JSON.stringify({ error: 'Fetch API returned HTTP ' + resp.status }); } + if (!resp.ok) { + const err = await resp.json().catch(() => ({})); + return JSON.stringify({ error: 'Fetch failed: ' + (err.error || `HTTP ${resp.status}`), status: resp.status, details: err.details || '' }); + } + // For POST/route, the response is raw text; for GET/extract it's JSON + if (method === 'POST') { + const text = await resp.text(); + return JSON.stringify({ method, content: text.substring(0, 4000), content_length: text.length }); + } const data = await resp.json(); - return JSON.stringify({ title: data.title || '', content: (data.content || '').substring(0, 4000), word_count: data.word_count || 0, method: data.method || 'extract' }); + return JSON.stringify({ method, title: data.title || '', content: (data.content || '').substring(0, 4000), word_count: data.word_count || 0, method_proxy: data.method || 'extract' }); } catch (e) { return JSON.stringify({ error: 'Fetch failed: ' + e.message }); } } case 'wpm_install': { |