@iambarryking/ag 3.0.1 → 3.1.0
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/README.md +88 -35
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +11 -21
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +214 -129
- package/dist/cli/repl.js.map +1 -1
- package/dist/core/agent.d.ts +8 -1
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +53 -12
- package/dist/core/agent.js.map +1 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/registry.d.ts +11 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +62 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/skills.d.ts +14 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +92 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/tools/memory.d.ts.map +1 -1
- package/dist/tools/memory.js +16 -10
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/skill.d.ts +6 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +20 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/tools/web.d.ts +3 -0
- package/dist/tools/web.d.ts.map +1 -0
- package/dist/tools/web.js +158 -0
- package/dist/tools/web.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { loadConfig, saveConfig } from '../core/config.js';
|
|
3
|
+
// ── HTML stripping (native fallback when Jina is unavailable) ─────────────
|
|
4
|
+
function stripHtml(html) {
|
|
5
|
+
let text = html;
|
|
6
|
+
// Remove script, style, nav, header, footer, aside blocks
|
|
7
|
+
text = text.replace(/<(script|style|nav|header|footer|aside)\b[^>]*>[\s\S]*?<\/\1>/gi, '');
|
|
8
|
+
// Try to extract article or main content
|
|
9
|
+
const article = text.match(/<(article|main)\b[^>]*>([\s\S]*?)<\/\1>/i);
|
|
10
|
+
if (article)
|
|
11
|
+
text = article[2];
|
|
12
|
+
// Convert headings to markdown-style
|
|
13
|
+
text = text.replace(/<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/gi, (_m, _l, content) => `\n## ${content.trim()}\n`);
|
|
14
|
+
// Convert links to text (url) format
|
|
15
|
+
text = text.replace(/<a\b[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, (_m, href, content) => {
|
|
16
|
+
const label = content.replace(/<[^>]+>/g, '').trim();
|
|
17
|
+
return href && !href.startsWith('#') ? `${label} (${href})` : label;
|
|
18
|
+
});
|
|
19
|
+
// Convert block elements to newlines
|
|
20
|
+
text = text.replace(/<\/?(p|div|li|tr|br)\b[^>]*\/?>/gi, '\n');
|
|
21
|
+
// Strip all remaining tags
|
|
22
|
+
text = text.replace(/<[^>]+>/g, '');
|
|
23
|
+
// Decode common HTML entities
|
|
24
|
+
text = text
|
|
25
|
+
.replace(/&/g, '&')
|
|
26
|
+
.replace(/</g, '<')
|
|
27
|
+
.replace(/>/g, '>')
|
|
28
|
+
.replace(/"/g, '"')
|
|
29
|
+
.replace(/'/g, "'")
|
|
30
|
+
.replace(/ /g, ' ');
|
|
31
|
+
// Collapse whitespace
|
|
32
|
+
text = text.replace(/[ \t]+/g, ' ');
|
|
33
|
+
text = text.replace(/\n{3,}/g, '\n\n');
|
|
34
|
+
return text.trim();
|
|
35
|
+
}
|
|
36
|
+
// ── Action handlers ───────────────────────────────────────────────────────
|
|
37
|
+
async function doFetch(url, raw) {
|
|
38
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
39
|
+
return 'Error: URL must start with http:// or https://';
|
|
40
|
+
}
|
|
41
|
+
const fetchOpts = { signal: AbortSignal.timeout(15_000) };
|
|
42
|
+
// Try Jina Reader first (returns clean markdown, handles JS-rendered pages)
|
|
43
|
+
if (!raw) {
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(`https://r.jina.ai/${url}`, {
|
|
46
|
+
...fetchOpts,
|
|
47
|
+
headers: { 'Accept': 'text/markdown' }
|
|
48
|
+
});
|
|
49
|
+
if (res.ok) {
|
|
50
|
+
const text = await res.text();
|
|
51
|
+
if (text.trim())
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Fall through to native fetch
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Native fetch fallback
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetch(url, fetchOpts);
|
|
62
|
+
if (!res.ok)
|
|
63
|
+
return `Fetch error: HTTP ${res.status}`;
|
|
64
|
+
const contentType = res.headers.get('content-type') || '';
|
|
65
|
+
if (contentType.includes('application/json')) {
|
|
66
|
+
const json = await res.json();
|
|
67
|
+
return JSON.stringify(json, null, 2);
|
|
68
|
+
}
|
|
69
|
+
const text = await res.text();
|
|
70
|
+
if (contentType.includes('text/html')) {
|
|
71
|
+
return stripHtml(text);
|
|
72
|
+
}
|
|
73
|
+
return text;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return `Fetch failed: ${error.message}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function ensureTavilyKey() {
|
|
80
|
+
const existing = process.env.TAVILY_API_KEY || loadConfig().tavilyApiKey;
|
|
81
|
+
if (existing)
|
|
82
|
+
return existing;
|
|
83
|
+
// Interactive prompt if TTY
|
|
84
|
+
if (process.stdin.isTTY) {
|
|
85
|
+
const C = await import('../core/colors.js').then(m => m.C);
|
|
86
|
+
console.error(`\n${C.bold}Web search requires a Tavily API key${C.reset}`);
|
|
87
|
+
console.error(`Sign up free (no credit card): ${C.cyan}https://app.tavily.com${C.reset}\n`);
|
|
88
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
89
|
+
const key = await new Promise(resolve => rl.question(`${C.yellow}Enter your Tavily API key:${C.reset} `, resolve));
|
|
90
|
+
rl.close();
|
|
91
|
+
const trimmed = key.trim();
|
|
92
|
+
if (!trimmed)
|
|
93
|
+
return null;
|
|
94
|
+
saveConfig({ tavilyApiKey: trimmed });
|
|
95
|
+
console.error(`${C.green}Key saved to config.${C.reset}\n`);
|
|
96
|
+
return trimmed;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
async function doSearch(query) {
|
|
101
|
+
const key = await ensureTavilyKey();
|
|
102
|
+
if (!key) {
|
|
103
|
+
return 'Error: Tavily API key not configured. Sign up free at https://tavily.com (no credit card needed), then set TAVILY_API_KEY env var or run /config set tavilyApiKey <key>';
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const res = await fetch('https://api.tavily.com/search', {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: { 'Content-Type': 'application/json' },
|
|
109
|
+
signal: AbortSignal.timeout(15_000),
|
|
110
|
+
body: JSON.stringify({ api_key: key, query, max_results: 5 })
|
|
111
|
+
});
|
|
112
|
+
if (!res.ok)
|
|
113
|
+
return `Search error: HTTP ${res.status}`;
|
|
114
|
+
const data = await res.json();
|
|
115
|
+
if (!data.results?.length)
|
|
116
|
+
return 'No results found.';
|
|
117
|
+
return data.results.map((r, i) => `${i + 1}. ${r.title || '(untitled)'}\n ${r.url || ''}\n ${r.content || ''}`).join('\n\n');
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
return `Search failed: ${error.message}`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// ── Exported tool ─────────────────────────────────────────────────────────
|
|
124
|
+
export function webTool() {
|
|
125
|
+
return {
|
|
126
|
+
type: 'function',
|
|
127
|
+
function: {
|
|
128
|
+
name: 'web',
|
|
129
|
+
description: 'Web operations. Actions: fetch (retrieve readable content from a URL), search (search the web for current information via Tavily).',
|
|
130
|
+
parameters: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
action: { type: 'string', enum: ['fetch', 'search'], description: 'The web operation to perform.' },
|
|
134
|
+
url: { type: 'string', description: 'URL to fetch (for action=fetch).' },
|
|
135
|
+
query: { type: 'string', description: 'Search query (for action=search).' },
|
|
136
|
+
raw: { type: 'boolean', description: 'If true, use native fetch + HTML stripping instead of Jina Reader (for action=fetch). Default: false.' }
|
|
137
|
+
},
|
|
138
|
+
required: ['action']
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
execute: async ({ action, url, query, raw }) => {
|
|
142
|
+
switch (action) {
|
|
143
|
+
case 'fetch': {
|
|
144
|
+
if (!url)
|
|
145
|
+
return 'Error: url is required for action=fetch.';
|
|
146
|
+
return doFetch(url, raw);
|
|
147
|
+
}
|
|
148
|
+
case 'search': {
|
|
149
|
+
if (!query)
|
|
150
|
+
return 'Error: query is required for action=search.';
|
|
151
|
+
return doSearch(query);
|
|
152
|
+
}
|
|
153
|
+
default: return `Unknown action "${action}". Use: fetch, search.`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/tools/web.ts"],"names":[],"mappings":"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"}
|