@bacnh85/pi-web 0.4.5 → 0.4.6

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.
Files changed (2) hide show
  1. package/extensions/index.ts +60 -75
  2. package/package.json +1 -1
@@ -38,15 +38,13 @@ const sharedControlSchema = {
38
38
  };
39
39
 
40
40
  const firecrawlControlSchema = {
41
- firecrawl_api_key: Type.Optional(Type.String({ description: "Firecrawl API key override. Prefer FIRECRAWL_API_KEY." })),
42
- firecrawl_api_url: Type.Optional(Type.String({ description: "Firecrawl API URL override. Defaults to FIRECRAWL_API_URL or hosted." })),
43
- timeout_ms: Type.Optional(Type.Number({ description: "Request timeout in milliseconds." })),
41
+ firecrawl_api_key: Type.Optional(Type.String({ description: "Override $FIRECRAWL_API_KEY." })),
42
+ firecrawl_api_url: Type.Optional(Type.String({ description: "Override $FIRECRAWL_API_URL." })),
44
43
  };
45
44
 
46
45
  const crawl4aiControlSchema = {
47
- crawl4ai_api_url: Type.Optional(Type.String({ description: "Crawl4AI API URL override. Defaults to CRAWL4AI_API_URL or http://172.30.55.22:11235." })),
48
- crawl4ai_api_token: Type.Optional(Type.String({ description: "Crawl4AI API token override. Prefer CRAWL4AI_API_TOKEN." })),
49
- timeout_ms: Type.Optional(Type.Number({ description: "Request timeout in milliseconds." })),
46
+ crawl4ai_api_url: Type.Optional(Type.String({ description: "Override $CRAWL4AI_API_URL." })),
47
+ crawl4ai_api_token: Type.Optional(Type.String({ description: "Override $CRAWL4AI_API_TOKEN." })),
50
48
  };
51
49
 
52
50
 
@@ -82,29 +80,26 @@ export default function piWebExtension(pi: ExtensionAPI) {
82
80
  name: "web_search",
83
81
  label: "Web Search",
84
82
  description:
85
- "Search the web. Auto-selects backends adaptively: SearXNG, Brave, Firecrawl.",
83
+ "Search the web. Auto-selects backends: SearXNG, Brave, Firecrawl.",
86
84
  promptSnippet: "Search current web results",
87
85
  promptGuidelines: [
88
- "Use web_search for source discovery, documentation lookup, current facts, and general web search.",
89
- "Backend auto-selection is adaptive: broad discovery uses SearXNG first; precision queries, site: searches, docs/source lookups, and include_content use Brave first; Firecrawl is last resort.",
90
- "If auto-selection returns poor-quality results, force backend: 'brave' or backend: 'searxng' for a different search index.",
91
- "Use the backend parameter to force a specific search engine (e.g., backend: 'brave').",
92
- "Use engines parameter for SearXNG tuning (e.g., engines: 'google,github' for technical queries).",
93
- "include_content prefers Brave automatically because only Brave search fetches inline page content; for other result URLs, use web_extract.",
94
- "Note: Firecrawl Search has poor semantic accuracy on domain-specific/ambiguous queries; prefer SearXNG or Brave for precision.",
95
- "Cite result URLs when web results materially support the answer.",
86
+ "Source discovery, docs, facts, and general search.",
87
+ "Broad discovery uses SearXNG; precision/site/docs use Brave; Firecrawl is fallback.",
88
+ "Force backend via backend:'brave'|'searxng' for poor auto results.",
89
+ "Use engines='google,github' for SearXNG tuning.",
90
+ "Cite source URLs.",
96
91
  ],
97
92
  parameters: Type.Object({
98
93
  query: Type.String(),
99
94
  count: Type.Optional(Type.Number({ default: 5 })),
100
- freshness: Type.Optional(Type.String({ description: "Time filter: e.g., 'pw' (past week), 'pm' (past month), 'py' (past year), or a date range like '2024-01-01to2024-06-30'." })),
95
+ freshness: Type.Optional(Type.String({ description: "Time filter: pw/pm/py or YYYY-MM-DDtoYYYY-MM-DD." })),
101
96
  country: Type.Optional(Type.String({ default: "US" })),
102
97
  backend: Type.Optional(Type.Union(
103
98
  [Type.Literal("auto"), Type.Literal("searxng"), Type.Literal("brave"), Type.Literal("firecrawl")],
104
- { default: "auto", description: "Search backend: auto (default), searxng, brave, or firecrawl." },
99
+ { default: "auto", description: "auto, searxng, brave, firecrawl." },
105
100
  )),
106
- engines: Type.Optional(Type.String({ description: "SearXNG engine override (e.g., 'google,github' for technical queries). Only used when backend is searxng or auto." })),
107
- include_content: Type.Optional(Type.Boolean({ default: false, description: "Fetch page content alongside search results. Slower but provides inline content." })),
101
+ engines: Type.Optional(Type.String({ description: "SearXNG engine list (google,github). Only for searxng/auto backend." })),
102
+ include_content: Type.Optional(Type.Boolean({ default: false, description: "Fetch inline page content (slower)." })),
108
103
  content_chars: Type.Optional(Type.Number({ default: 5000 })),
109
104
  ...sharedControlSchema,
110
105
  }),
@@ -133,30 +128,26 @@ export default function piWebExtension(pi: ExtensionAPI) {
133
128
  name: "web_extract",
134
129
  label: "Web Content Extraction",
135
130
  description:
136
- "Extract readable content from a URL. Auto backend: static \u2192 dynamic \u2192 full.",
131
+ "Extract readable content from a URL. Auto mode: static\u2192dynamic\u2192full.",
137
132
  promptSnippet: "Extract readable webpage content as markdown",
138
133
  promptGuidelines: [
139
- "Use web_extract to get clean markdown content from a known URL.",
140
- "Use mode: 'static' for simple static pages (fast, no API key needed, uses JSDOM+Readability).",
141
- "Use mode: 'dynamic' for JavaScript-rendered pages (uses Firecrawl Scrape).",
142
- "Use mode: 'full' for pages that need Crawl4AI rendering when other modes fail (resource-intensive).",
143
- "Default mode 'auto' tries static → dynamic → full. Successive fallbacks are noted in output.",
144
- "⚠️ Dynamic mode (Firecrawl Scrape) may fail on bot-protected sites (Ansible docs, CDN-backed doc sites). Full mode (Crawl4AI) handles more sites but is heavier.",
145
- "If all extraction modes fail, try web_screenshot for a visual snapshot, or the page may require interactive login.",
146
- "Use the prompt and schema parameters for structured JSON extraction (dynamic mode only); structured JSON is returned in details and text when available.",
147
- "Cite the source URL when using extracted content in an answer.",
134
+ "Clean markdown from a known URL.",
135
+ "mode: 'static' (no API key, JSDOM), 'dynamic' (Firecrawl JS), 'full' (Crawl4AI).",
136
+ "'auto' tries static\u2192dynamic\u2192full; see diagnostics for fallback chain.",
137
+ "Use prompt+schema for structured JSON extraction (dynamic mode only).",
138
+ "Cite the source URL.",
148
139
  ],
149
140
  parameters: Type.Object({
150
141
  url: Type.String(),
151
142
  mode: Type.Optional(Type.Union(
152
143
  [Type.Literal("auto"), Type.Literal("static"), Type.Literal("dynamic"), Type.Literal("full")],
153
- { default: "auto", description: "Extraction mode: auto (default), static, dynamic, or full." },
144
+ { default: "auto", description: "auto, static, dynamic, full." },
154
145
  )),
155
146
  prompt: Type.Optional(Type.String({ description: "Prompt for structured JSON extraction (dynamic mode only)." })),
156
147
  schema: Type.Optional(Type.Any({ description: "JSON schema for structured extraction (dynamic mode only)." })),
157
148
  content_chars: Type.Optional(Type.Number({ default: 20000 })),
158
- wait_for: Type.Optional(Type.Number({ description: "Milliseconds to wait for Firecrawl dynamic rendering before extraction. Full mode uses Crawl4AI /md and may ignore this." })),
159
- mobile: Type.Optional(Type.Boolean({ default: false, description: "Emulate mobile viewport (dynamic mode only)." })),
149
+ wait_for: Type.Optional(Type.Number({ description: "Ms to wait for Firecrawl render before extraction." })),
150
+ mobile: Type.Optional(Type.Boolean({ default: false, description: "Mobile viewport (dynamic mode only)." })),
160
151
  ...sharedControlSchema,
161
152
  }),
162
153
  async execute(_id: string, params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
@@ -184,24 +175,23 @@ export default function piWebExtension(pi: ExtensionAPI) {
184
175
  name: "web_map",
185
176
  label: "Site URL Discovery",
186
177
  description:
187
- "Discover URLs from a site using Firecrawl Map.",
178
+ "Discover site URLs via Firecrawl Map.",
188
179
  promptSnippet: "Map site URLs",
189
180
  promptGuidelines: [
190
- "Use web_map to discover URLs from a site before crawling or targeted extraction.",
191
- "Works best on base domains (e.g., https://example.com). Returns fewer results on sub-paths; use sitemap: 'only' for sitemap-only discovery on sub-paths.",
192
- "Use sitemap: 'only' for sitemap-only discovery.",
193
- "Use mapped URLs with web_extract for targeted extraction instead of web_crawl when only a few pages are needed.",
194
- "Keep limits small unless broad site discovery is explicitly requested.",
181
+ "Discover site URLs before crawling. Prefer web_extract for small jobs.",
182
+ "Best on base domains. sitemap:'only' for sub-path discovery.",
183
+ "Keep limits small unless broad discovery is requested.",
195
184
  ],
196
185
  parameters: Type.Object({
197
186
  url: Type.String(),
198
187
  limit: Type.Optional(Type.Number({ default: 100 })),
199
188
  include_subdomains: Type.Optional(Type.Boolean({ default: false })),
200
- search: Type.Optional(Type.String({ description: "Optional search query to guide URL discovery (semantic map)." })),
201
- sitemap: Type.Optional(Type.Union([Type.Literal("only"), Type.Literal("include"), Type.Literal("skip")], { description: "Sitemap mode: include (default), only (sitemap-only), or skip." })),
202
- use_index: Type.Optional(Type.Boolean({ default: true, description: "Whether to use the Firecrawl search index for URL discovery." })),
203
- ignore_cache: Type.Optional(Type.Boolean({ default: false, description: "Ignore cached map results." })),
189
+ search: Type.Optional(Type.String({ description: "Search query to guide URL discovery (semantic map)." })),
190
+ sitemap: Type.Optional(Type.Union([Type.Literal("only"), Type.Literal("include"), Type.Literal("skip")], { description: "only, include(default), skip." })),
191
+ use_index: Type.Optional(Type.Boolean({ default: true, description: "Use Firecrawl index for discovery." })),
192
+ ignore_cache: Type.Optional(Type.Boolean({ default: false, description: "Ignore cached results." })),
204
193
  ...firecrawlControlSchema,
194
+ ...sharedControlSchema,
205
195
  }),
206
196
  async execute(_id: string, params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
207
197
  const body: Record<string, unknown> = {
@@ -228,30 +218,27 @@ export default function piWebExtension(pi: ExtensionAPI) {
228
218
  name: "web_crawl",
229
219
  label: "Site Crawl",
230
220
  description:
231
- "Crawl site pages. Firecrawl 'light' or Crawl4AI 'full' headless mode.",
221
+ "Crawl pages. Firecrawl 'light' or Crawl4AI 'full' headless mode.",
232
222
  promptSnippet: "Crawl a small site section",
233
223
  promptGuidelines: [
234
- "Use web_crawl only when multiple pages from a site are truly needed; prefer web_map + web_extract for small numbers of pages.",
235
- "Use mode: 'light' (default) for conservative Firecrawl crawling of docs/sites.",
236
- "Use mode: 'full' for Crawl4AI crawling with full rendered data (JS, media, links). More resource-intensive.",
237
- "For Firecrawl mode ('light'), use the url parameter with optional include_paths/exclude_paths.",
238
- "For Crawl4AI mode ('full'), use the urls (array) parameter for batch crawling up to 100 URLs.",
239
- "Keep limits conservative (default 10) unless the user explicitly requests large crawls.",
240
- "Try web_map first to identify candidate URLs and pass them to web_extract before resorting to a full crawl.",
224
+ "Prefer web_map + web_extract over crawl for small jobs.",
225
+ "'light'=Firecrawl (url param), 'full'=Crawl4AI (urls[] param).",
226
+ "Keep limit low (default 10).",
241
227
  ],
242
228
  parameters: Type.Object({
243
- url: Type.Optional(Type.String({ description: "URL for Firecrawl-style single-page crawl (mode: 'light')." })),
244
- urls: Type.Optional(Type.Array(Type.String(), { description: "URLs for Crawl4AI-style multi-URL crawl (mode: 'full'), up to 100." })),
245
- mode: Type.Optional(Type.Union([Type.Literal("light"), Type.Literal("full")], { default: "light", description: "Crawl mode: 'light' (Firecrawl, conservative) or 'full' (Crawl4AI, rendered data)." })),
229
+ url: Type.Optional(Type.String({ description: "URL for Firecrawl-style crawl (mode:'light')." })),
230
+ urls: Type.Optional(Type.Array(Type.String(), { description: "URLs for Crawl4AI-style crawl (mode:'full'), up to 100." })),
231
+ mode: Type.Optional(Type.Union([Type.Literal("light"), Type.Literal("full")], { default: "light", description: "'light'(Firecrawl) or 'full'(Crawl4AI)." })),
246
232
  limit: Type.Optional(Type.Number({ default: 10 })),
247
- include_paths: Type.Optional(Type.String({ description: "Comma-separated path patterns to include (Firecrawl mode only)." })),
248
- exclude_paths: Type.Optional(Type.String({ description: "Comma-separated path patterns to exclude (Firecrawl mode only)." })),
249
- poll: Type.Optional(Type.Boolean({ default: false, description: "Poll for crawl completion (Firecrawl mode only)." })),
250
- browser_config: Type.Optional(Type.Any({ description: "Optional BrowserConfig JSON object (Crawl4AI mode only)." })),
251
- crawler_config: Type.Optional(Type.Any({ description: "Optional CrawlerRunConfig JSON object (Crawl4AI mode only)." })),
233
+ include_paths: Type.Optional(Type.String({ description: "Comma-separated paths to include (Firecrawl mode)." })),
234
+ exclude_paths: Type.Optional(Type.String({ description: "Comma-separated paths to exclude (Firecrawl mode)." })),
235
+ poll: Type.Optional(Type.Boolean({ default: false, description: "Poll for completion (Firecrawl mode)." })),
236
+ browser_config: Type.Optional(Type.Any({ description: "BrowserConfig JSON (full mode only)." })),
237
+ crawler_config: Type.Optional(Type.Any({ description: "CrawlerRunConfig JSON (full mode only)." })),
252
238
  content_chars: Type.Optional(Type.Number({ default: 20000 })),
253
239
  ...firecrawlControlSchema,
254
240
  ...crawl4aiControlSchema,
241
+ ...sharedControlSchema,
255
242
  }),
256
243
  async execute(_id: string, params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
257
244
  const mode = (params.mode as string) || "light";
@@ -319,19 +306,18 @@ export default function piWebExtension(pi: ExtensionAPI) {
319
306
  name: "web_screenshot",
320
307
  label: "Web Page Screenshot",
321
308
  description:
322
- "Capture a full-page PNG screenshot via Crawl4AI headless browser.",
309
+ "Full-page PNG screenshot via Crawl4AI.",
323
310
  promptSnippet: "Screenshot a webpage",
324
311
  promptGuidelines: [
325
- "Use web_screenshot when a visual snapshot of a rendered page is needed, or when web_extract fails on a heavily JS-dependent or bot-protected page.",
326
- "The screenshot is returned as a base64-encoded PNG string.",
327
- "Use wait_for to delay capture for dynamic content to render (default 2 seconds).",
328
- "Use wait_for_images to ensure images are loaded before capture.",
312
+ "Use when web_extract fails on JS-heavy or bot-protected pages.",
313
+ "wait_for (default 2s) delays capture for dynamic content.",
329
314
  ],
330
315
  parameters: Type.Object({
331
316
  url: Type.String(),
332
- wait_for: Type.Optional(Type.Number({ default: 2, description: "Seconds to wait before capturing screenshot." })),
333
- wait_for_images: Type.Optional(Type.Boolean({ default: false, description: "Wait for images to load before capture." })),
317
+ wait_for: Type.Optional(Type.Number({ default: 2, description: "Seconds to wait before capture." })),
318
+ wait_for_images: Type.Optional(Type.Boolean({ default: false, description: "Wait for images before capture." })),
334
319
  ...crawl4aiControlSchema,
320
+ ...sharedControlSchema,
335
321
  }),
336
322
  async execute(_id: string, params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
337
323
  const config = loadCrawl4aiConfig(params as Record<string, unknown>, cwdFromContext(ctx), includeProjectEnv(ctx));
@@ -360,15 +346,16 @@ export default function piWebExtension(pi: ExtensionAPI) {
360
346
  name: "web_pdf",
361
347
  label: "Web Page PDF",
362
348
  description:
363
- "Generate a PDF document via Crawl4AI headless browser.",
349
+ "PDF document via Crawl4AI.",
364
350
  promptSnippet: "PDF a webpage",
365
351
  promptGuidelines: [
366
- "Use web_pdf when a printable or archivable snapshot of a page is needed.",
367
- "The PDF is returned as a base64-encoded string.",
352
+ "Printable or archivable page snapshot.",
353
+ "Returns base64 PDF string.",
368
354
  ],
369
355
  parameters: Type.Object({
370
356
  url: Type.String(),
371
357
  ...crawl4aiControlSchema,
358
+ ...sharedControlSchema,
372
359
  }),
373
360
  async execute(_id: string, params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
374
361
  const config = loadCrawl4aiConfig(params as Record<string, unknown>, cwdFromContext(ctx), includeProjectEnv(ctx));
@@ -389,14 +376,12 @@ export default function piWebExtension(pi: ExtensionAPI) {
389
376
  name: "web_status",
390
377
  label: "Web Provider Status",
391
378
  description:
392
- "Show web provider configuration status without printing secrets.",
393
- promptSnippet: "Check web provider configuration and server status",
379
+ "Show web provider config status without printing secrets.",
380
+ promptSnippet: "Check web provider config and server status",
394
381
  promptGuidelines: [
395
- "Use web_status when web tools fail due to missing credentials/config or to verify which backends are available.",
396
- "The output shows which backends are configured; if a backend is missing, configure its env vars.",
397
- "Never print API key values; this tool reports only presence and source.",
398
- "Shows Crawl4AI server health, version, and auth status when the server is reachable.",
399
- "For Firecrawl, `apiKeyFound: false` is normal for self-hosted instances without auth. Use the `ready` field to check whether Firecrawl is actually usable.",
382
+ "Check which backends are configured and their server status.",
383
+ "Never prints secrets reports only presence and source.",
384
+ "apiKeyFound:false is normal for self-hosted Firecrawl; check ready field.",
400
385
  ],
401
386
  parameters: Type.Object({}),
402
387
  async execute(_id: string, _params: Record<string, unknown>, signal: AbortSignal, _onUpdate: unknown, ctx: any) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-web",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Pi extension for web search, page extraction, Firecrawl scraping/crawling, and Crawl4AI headless browser crawling.",
5
5
  "type": "module",
6
6
  "license": "MIT",