@demigodmode/pi-web-agent 0.1.0 → 0.2.2

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 (78) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +63 -176
  3. package/dist/extension.js +0 -25
  4. package/dist/scripts/live-web-eval.d.ts +1 -0
  5. package/dist/scripts/live-web-eval.js +411 -0
  6. package/dist/src/cache/ttl-cache.d.ts +8 -0
  7. package/dist/src/cache/ttl-cache.js +21 -0
  8. package/dist/src/extension.d.ts +2 -0
  9. package/dist/src/extension.js +155 -0
  10. package/dist/src/extract/readability.d.ts +8 -0
  11. package/dist/src/extract/readability.js +93 -0
  12. package/dist/src/fetch/browser-resolution.d.ts +15 -0
  13. package/dist/src/fetch/browser-resolution.js +55 -0
  14. package/dist/src/fetch/headless-fetch.d.ts +18 -0
  15. package/dist/src/fetch/headless-fetch.js +87 -0
  16. package/dist/src/fetch/http-fetch.d.ts +4 -0
  17. package/dist/src/fetch/http-fetch.js +50 -0
  18. package/dist/src/orchestration/index.d.ts +41 -0
  19. package/dist/src/orchestration/index.js +9 -0
  20. package/dist/src/orchestration/research-orchestrator.d.ts +43 -0
  21. package/dist/src/orchestration/research-orchestrator.js +87 -0
  22. package/dist/src/orchestration/research-types.d.ts +41 -0
  23. package/dist/src/orchestration/research-types.js +1 -0
  24. package/dist/src/orchestration/research-worker.d.ts +16 -0
  25. package/dist/src/orchestration/research-worker.js +131 -0
  26. package/dist/src/search/duckduckgo.d.ts +9 -0
  27. package/dist/src/search/duckduckgo.js +52 -0
  28. package/dist/src/tools/web-explore.d.ts +44 -0
  29. package/dist/src/tools/web-explore.js +50 -0
  30. package/dist/src/tools/web-fetch-headless.d.ts +6 -0
  31. package/dist/src/tools/web-fetch-headless.js +14 -0
  32. package/dist/src/tools/web-fetch.d.ts +6 -0
  33. package/dist/src/tools/web-fetch.js +14 -0
  34. package/dist/src/tools/web-search.d.ts +10 -0
  35. package/dist/src/tools/web-search.js +103 -0
  36. package/dist/src/types.d.ts +48 -0
  37. package/dist/src/types.js +7 -0
  38. package/dist/tests/cache/ttl-cache.test.d.ts +1 -0
  39. package/dist/tests/cache/ttl-cache.test.js +19 -0
  40. package/dist/tests/contracts.test.d.ts +1 -0
  41. package/dist/tests/contracts.test.js +65 -0
  42. package/dist/tests/extension.test.d.ts +1 -0
  43. package/dist/tests/extension.test.js +123 -0
  44. package/dist/tests/extract/readability.test.d.ts +1 -0
  45. package/dist/tests/extract/readability.test.js +79 -0
  46. package/dist/tests/fetch/browser-resolution.test.d.ts +1 -0
  47. package/dist/tests/fetch/browser-resolution.test.js +37 -0
  48. package/dist/tests/fetch/headless-fetch.smoke.test.d.ts +1 -0
  49. package/dist/tests/fetch/headless-fetch.smoke.test.js +17 -0
  50. package/dist/tests/fetch/headless-fetch.test.d.ts +1 -0
  51. package/dist/tests/fetch/headless-fetch.test.js +150 -0
  52. package/dist/tests/fetch/http-fetch.test.d.ts +1 -0
  53. package/dist/tests/fetch/http-fetch.test.js +129 -0
  54. package/dist/tests/orchestration/research-orchestrator.test.d.ts +1 -0
  55. package/dist/tests/orchestration/research-orchestrator.test.js +298 -0
  56. package/dist/tests/orchestration/research-worker.test.d.ts +1 -0
  57. package/dist/tests/orchestration/research-worker.test.js +171 -0
  58. package/dist/tests/orchestration/research-workflow.test.d.ts +1 -0
  59. package/dist/tests/orchestration/research-workflow.test.js +119 -0
  60. package/dist/tests/package-manifest.test.d.ts +1 -0
  61. package/dist/tests/package-manifest.test.js +29 -0
  62. package/dist/tests/release-foundation.test.d.ts +1 -0
  63. package/dist/tests/release-foundation.test.js +16 -0
  64. package/dist/tests/release-script.test.d.ts +1 -0
  65. package/dist/tests/release-script.test.js +72 -0
  66. package/dist/tests/search/duckduckgo.test.d.ts +1 -0
  67. package/dist/tests/search/duckduckgo.test.js +103 -0
  68. package/dist/tests/tools/web-explore.test.d.ts +1 -0
  69. package/dist/tests/tools/web-explore.test.js +163 -0
  70. package/dist/tests/tools/web-fetch-headless.test.d.ts +1 -0
  71. package/dist/tests/tools/web-fetch-headless.test.js +31 -0
  72. package/dist/tests/tools/web-fetch.test.d.ts +1 -0
  73. package/dist/tests/tools/web-fetch.test.js +27 -0
  74. package/dist/tests/tools/web-search.test.d.ts +1 -0
  75. package/dist/tests/tools/web-search.test.js +125 -0
  76. package/dist/vitest.config.d.ts +2 -0
  77. package/dist/vitest.config.js +13 -0
  78. package/package.json +9 -2
package/README.md CHANGED
@@ -1,176 +1,63 @@
1
- # pi-web-agent
2
-
3
- `@demigodmode/pi-web-agent` is a Pi package for reliable web access.
4
-
5
- It is built around a simple rule: searching for a page is not the same thing as reading it. This package keeps those steps separate, prefers plain HTTP by default, and is designed to say "I couldn't read this reliably" instead of making something up.
6
-
7
- ## What it does
8
-
9
- The package is built around three tools:
10
-
11
- - `web_search` finds relevant pages and returns titles, URLs, and snippets
12
- - `web_fetch` fetches a specific page over plain HTTP and tries to extract readable content
13
- - `web_fetch_headless` is the explicit browser-based path for pages that need rendering
14
-
15
- The boundary between those tools is intentional.
16
-
17
- `web_search` is for discovery. It should not imply that a page was fetched.
18
-
19
- `web_fetch` is for reading a page over HTTP. If the result looks weak, incomplete, blocked, or too script-heavy, it should return `needs_headless` instead of bluffing.
20
-
21
- `web_fetch_headless` exists for the cases where a browser really is required. It is opt-in only.
22
-
23
- ## Why this exists
24
-
25
- A lot of web tooling in coding agents gets fuzzy in exactly the wrong places. Search results get treated like page reads. Browser fallback happens behind the scenes. Failures get softened into fake confidence.
26
-
27
- This package is trying to do the opposite.
28
-
29
- The rules are straightforward:
30
-
31
- - no hidden browser launch
32
- - no automatic HTTP-to-headless fallback
33
- - no claiming a page was read when only snippets were available
34
- - explicit structured failure when the result is incomplete or blocked
35
-
36
- ## What makes it different
37
-
38
- The main thing is the contract.
39
-
40
- `web_search` discovers sources.
41
-
42
- `web_fetch` reads over HTTP only.
43
-
44
- `web_fetch_headless` is the explicit browser path.
45
-
46
- That separation is the whole point. It makes failures easier to reason about and avoids the weird behavior where a tool quietly changes execution mode behind your back.
47
-
48
- ## Install
49
-
50
- Install it through Pi:
51
-
52
- ```bash
53
- pi install npm:@demigodmode/pi-web-agent
54
- ```
55
-
56
- Update installed packages later with:
57
-
58
- ```bash
59
- pi update
60
- ```
61
-
62
- If you just want to inspect the package from npm directly, the package name is:
63
-
64
- ```bash
65
- npm view @demigodmode/pi-web-agent
66
- ```
67
-
68
- ## Current status
69
-
70
- This repo is in early MVP shape, but it is no longer just a design doc.
71
-
72
- Right now it has:
73
-
74
- - a TypeScript project scaffold
75
- - shared result and status contracts
76
- - a DuckDuckGo HTML parser for `web_search`
77
- - an HTTP fetch path with readability-based extraction and conservative escalation to `needs_headless`
78
- - a real browser-backed `web_fetch_headless` implementation with local browser resolution
79
- - repo-local Pi extension wiring for development
80
- - a test suite around parser behavior, contracts, extraction, caching, and tool adapters
81
- - optional smoke coverage for local installed browsers
82
-
83
- So the project is real and usable, but still early.
84
-
85
- ## Example behavior
86
-
87
- These are conceptual examples of the contract the package is aiming to expose.
88
-
89
- ### Search
90
-
91
- `web_search("pi coding agent")`
92
-
93
- Returns discovery results like:
94
-
95
- - title
96
- - URL
97
- - snippet
98
-
99
- It does not imply the page was fetched.
100
-
101
- ### HTTP fetch
102
-
103
- `web_fetch("https://example.com/article")`
104
-
105
- If the page is readable over plain HTTP, it should return extracted content.
106
-
107
- If the page looks too script-heavy, too thin, blocked, or otherwise unreliable, it should return `needs_headless` instead of pretending the extraction is good enough.
108
-
109
- ### Explicit headless fetch
110
-
111
- `web_fetch_headless("https://example.com/app")`
112
-
113
- This is the browser-based path for pages that really need rendering.
114
-
115
- This path now launches a local browser explicitly, waits for the rendered page to settle, and then extracts readable content from the rendered HTML.
116
-
117
- ## Local development
118
-
119
- Install dependencies:
120
-
121
- ```bash
122
- npm install
123
- ```
124
-
125
- Run tests with coverage:
126
-
127
- ```bash
128
- npm test
129
- ```
130
-
131
- Run the typecheck used as lint:
132
-
133
- ```bash
134
- npm run lint
135
- ```
136
-
137
- Build the project:
138
-
139
- ```bash
140
- npm run build
141
- ```
142
-
143
- To run the optional real-browser smoke test for headless fetch, set `PI_HEADLESS_SMOKE=1` before running Vitest. It stays skipped by default so local browser install differences do not make the normal test suite flaky.
144
-
145
- Coverage is now part of the normal `npm test` flow. Vitest prints a text summary in the terminal and writes the full HTML report to `coverage/`.
146
-
147
- ### Trying it in Pi locally
148
-
149
- This repo includes a project-local Pi extension entrypoint at `.pi/extensions/pi-web-agent.ts` for development and hot reload.
150
-
151
- For the published npm package, Pi loads the compiled runtime from `dist/extension.js` via the `pi.extensions` entry in `package.json`.
152
-
153
- After starting Pi in this project, use `/reload` if you change the extension code and want Pi to pick up the latest version.
154
-
155
- ## Project layout
156
-
157
- The code is split into small modules on purpose.
158
-
159
- - `src/extension.ts` - package entry surface
160
- - `src/tools/` - thin tool adapters
161
- - `src/search/` - search backend logic
162
- - `src/fetch/` - HTTP and headless fetch logic
163
- - `src/extract/` - readable-content extraction
164
- - `src/cache/` - small cache utilities
165
- - `src/types.ts` - shared contracts
166
- - `tests/` - parser, contract, extraction, fetch, and adapter tests
167
-
168
- ## Near-term next steps
169
-
170
- The next chunk of work is pretty clear:
171
-
172
- - keep tightening weak-content escalation on tricky HTTP targets
173
- - improve cleanup of noisy rendered-page extraction on busy sites
174
- - expand fixtures and end-to-end coverage
175
- - add alternate search backends behind a first-class provider abstraction
176
-
1
+ # pi-web-agent
2
+
3
+ [![CI](https://github.com/demigodmode/pi-web-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/demigodmode/pi-web-agent/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@demigodmode/pi-web-agent)](https://www.npmjs.com/package/@demigodmode/pi-web-agent)
5
+ [![Docs](https://img.shields.io/badge/docs-github%20pages-blue)](https://demigodmode.github.io/pi-web-agent/)
6
+
7
+ `@demigodmode/pi-web-agent` is a Pi package for web access.
8
+
9
+ The whole point is keeping the boundaries straight:
10
+
11
+ - `web_search` is for discovery
12
+ - `web_fetch` is for plain HTTP reads
13
+ - `web_fetch_headless` is the explicit browser path
14
+ - `web_explore` is the bounded research path
15
+
16
+ That sounds obvious, but a lot of agent tooling gets fuzzy right there. This package is meant to be stricter about what it actually did and more willing to say when a read was not good enough to trust.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pi install npm:@demigodmode/pi-web-agent
22
+ ```
23
+
24
+ Later on, update installed packages with:
25
+
26
+ ```bash
27
+ pi update
28
+ ```
29
+
30
+ ## Docs
31
+
32
+ Docs site:
33
+
34
+ - https://demigodmode.github.io/pi-web-agent/
35
+
36
+ Work on the docs locally:
37
+
38
+ ```bash
39
+ npm run docs:dev
40
+ ```
41
+
42
+ Build the docs:
43
+
44
+ ```bash
45
+ npm run docs:build
46
+ ```
47
+
48
+ ## Local development
49
+
50
+ ```bash
51
+ npm install
52
+ npm test
53
+ npm run lint
54
+ npm run build
55
+ ```
56
+
57
+ For local Pi work, this repo includes `.pi/extensions/pi-web-agent.ts`.
58
+
59
+ If Pi is already running, use `/reload` after changes.
60
+
61
+ ## License
62
+
63
+ AGPL-3.0-only. See `LICENSE`.
package/dist/extension.js CHANGED
@@ -3,14 +3,6 @@ import { createWebExploreTool } from './tools/web-explore.js';
3
3
  import { createWebFetchTool } from './tools/web-fetch.js';
4
4
  import { createWebFetchHeadlessTool } from './tools/web-fetch-headless.js';
5
5
  import { createWebSearchTool } from './tools/web-search.js';
6
- const WEB_EXPLORE_REMINDER_TYPE = 'pi-web-agent-web-explore-reminder';
7
- const WEB_EXPLORE_REMINDER = 'web_explore has already been used for this research task. Only call low-level web tools if there is a specific unresolved gap. Do not keep searching or fetching just for extra confirmation.';
8
- function hasSuccessfulWebExplore(messages) {
9
- return messages.some((message) => message.role === 'toolResult' && message.toolName === 'web_explore' && !message.isError);
10
- }
11
- function hasWebExploreReminder(messages) {
12
- return messages.some((message) => message.role === 'custom' && message.customType === WEB_EXPLORE_REMINDER_TYPE);
13
- }
14
6
  export default function extension(pi) {
15
7
  const webSearch = createWebSearchTool();
16
8
  const webFetch = createWebFetchTool();
@@ -25,23 +17,6 @@ export default function extension(pi) {
25
17
  'Do not keep searching or fetching just for extra confirmation.'
26
18
  };
27
19
  });
28
- pi.on('context', async (event) => {
29
- if (!hasSuccessfulWebExplore(event.messages) || hasWebExploreReminder(event.messages)) {
30
- return { messages: event.messages };
31
- }
32
- return {
33
- messages: [
34
- ...event.messages,
35
- {
36
- role: 'custom',
37
- customType: WEB_EXPLORE_REMINDER_TYPE,
38
- content: WEB_EXPLORE_REMINDER,
39
- display: false,
40
- timestamp: Date.now()
41
- }
42
- ]
43
- };
44
- });
45
20
  pi.registerTool({
46
21
  name: 'web_search',
47
22
  label: 'Web Search',
@@ -0,0 +1 @@
1
+ export {};