@normful/parallel-web-pi-extension 0.0.0-stage → 1.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/LICENSE +23 -0
- package/README.md +249 -2
- package/package.json +64 -4
- package/src/index.ts +362 -0
- package/src/oauth/index.ts +256 -0
- package/src/parallel-auth.ts +116 -0
- package/src/parallel-client.ts +84 -0
- package/src/parallel-responses.ts +304 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Parallel Web
|
|
4
|
+
Copyright (c) 2026 Norman Sue
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
23
|
+
|
package/README.md
CHANGED
|
@@ -1,3 +1,250 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @normful/parallel-web-pi-extension
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pi extension that adds `web_search`, `web_fetch`, and `web_research` backed by
|
|
4
|
+
Parallel. Keep your usual coding agent and give it web tools with one install.
|
|
5
|
+
|
|
6
|
+
This is a fork: a manually maintained copy of `@parallel-web/pi-extension` 1.3.0
|
|
7
|
+
from `parallel-web/parallel-npm-packages`, renamed and released here. The
|
|
8
|
+
upstream `@parallel-web/oauth` helper (private on npm) is vendored into
|
|
9
|
+
`src/oauth/` so the package builds and tests standalone.
|
|
10
|
+
|
|
11
|
+
Install it with:
|
|
12
|
+
```
|
|
13
|
+
pi install npm:@normful/parallel-web-pi-extension
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What It Does
|
|
17
|
+
|
|
18
|
+
- Registers `web_search`
|
|
19
|
+
- Registers `web_fetch`
|
|
20
|
+
- Registers `web_research` for synthesized answers with sources through the
|
|
21
|
+
Responses API
|
|
22
|
+
- Registers a `parallel` auth provider, so Pi's own `/login parallel` runs the
|
|
23
|
+
Parallel browser OAuth flow and stores the API key in Pi's auth store
|
|
24
|
+
(`auth.json`) alongside every other provider credential
|
|
25
|
+
- Adds a `parallel-login` command that reports current auth status
|
|
26
|
+
|
|
27
|
+
Auth resolution order (owned by Pi, not the extension):
|
|
28
|
+
|
|
29
|
+
1. The credential Pi stored for provider `parallel`
|
|
30
|
+
2. `PARALLEL_API_KEY`
|
|
31
|
+
|
|
32
|
+
Run `/parallel-login` inside Pi to check whether Parallel is configured. To
|
|
33
|
+
remove a stored credential, run `/logout` and select Parallel. Environment
|
|
34
|
+
variables are not affected by Pi's logout flow.
|
|
35
|
+
|
|
36
|
+
Requires `@earendil-works/pi-coding-agent` 0.83.0 or newer.
|
|
37
|
+
|
|
38
|
+
## Web Research
|
|
39
|
+
|
|
40
|
+
After installing this extension, run `/login parallel` and ask your usual Pi
|
|
41
|
+
agent a research question. No additional package or model selection is needed:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
Compare the current Node.js compatibility of Node and Bun for a production API server. Research the tradeoffs and cite primary sources.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The agent can call the research tool directly:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
web_research({
|
|
51
|
+
query: "Compare the current Node.js compatibility of Node and Bun for a production API server. Cite primary sources.",
|
|
52
|
+
effort: "medium"
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Tool | Use it for |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `web_research` | A complete answer that needs web research and synthesis |
|
|
59
|
+
| `web_search` | Discovering sources and raw excerpts to investigate yourself |
|
|
60
|
+
| `web_fetch` | Reading known URLs or checking original sources |
|
|
61
|
+
|
|
62
|
+
Start with a complete, self-contained `query`. Research does not see the Pi
|
|
63
|
+
conversation or local files, so include relevant constraints and only context
|
|
64
|
+
that is safe to send.
|
|
65
|
+
|
|
66
|
+
When available, the result starts with a `Response ID`. For a focused follow-up
|
|
67
|
+
on the same investigation, pass that ID as `previous_response_id`:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
web_research({
|
|
71
|
+
query: "Which of those compatibility gaps would matter for an API server that uses native Node.js addons?",
|
|
72
|
+
previous_response_id: "resp_..." // Copy the actual ID from the previous result.
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Use the new ID returned by each follow-up to continue from its answer. Omit the
|
|
77
|
+
ID for a new or unrelated question. Calls never chain automatically, and the
|
|
78
|
+
extension keeps no local research-session state. Continuation reuses saved
|
|
79
|
+
research context, including earlier answer summaries, not every internal step
|
|
80
|
+
of the research process. IDs are opaque; the tool accepts non-empty IDs up to
|
|
81
|
+
512 characters without whitespace or control characters.
|
|
82
|
+
|
|
83
|
+
Saved context is not guaranteed to remain available, and continuation is not
|
|
84
|
+
supported for zero data retention (ZDR) accounts. An unavailable ID or a ZDR
|
|
85
|
+
restriction returns an error without retrying as fresh research. A valid
|
|
86
|
+
answer without a usable new ID is still returned, but cannot be continued
|
|
87
|
+
through that result. If Pi loses an ID during conversation compaction, do not
|
|
88
|
+
invent a replacement.
|
|
89
|
+
|
|
90
|
+
`effort` is optional and defaults to `medium`, matching the Responses API
|
|
91
|
+
default. Use `low` for focused lookups, `medium` for general research, and
|
|
92
|
+
`high` for extensive research. Responses is billed per successful call; see
|
|
93
|
+
the [current pricing](https://docs.parallel.ai/getting-started/pricing).
|
|
94
|
+
|
|
95
|
+
Each invocation makes one non-streaming `POST /v1/responses` request, with no
|
|
96
|
+
automatic retries or background jobs. The local deadline
|
|
97
|
+
is 120 seconds, including reading the response; slower valid research can
|
|
98
|
+
exceed this client limit. Cancelling the tool
|
|
99
|
+
aborts the local request on a best-effort basis; it does not confirm that work
|
|
100
|
+
stopped on the server. A manual retry is a new request and may incur a new charge.
|
|
101
|
+
|
|
102
|
+
The request contains only the fixed research instructions and explicit query,
|
|
103
|
+
with the selected effort and `previous_response_id` only when explicitly
|
|
104
|
+
supplied. It does not automatically forward parent history,
|
|
105
|
+
local files, cwd, environment variables, Pi tools, or session metadata.
|
|
106
|
+
Anything the calling agent includes in `query` is sent to Parallel.
|
|
107
|
+
|
|
108
|
+
The tool rejects requests over 20,000 combined instruction and input
|
|
109
|
+
characters, including the separator the API counts, before sending them.
|
|
110
|
+
It preserves the answer and renders returned HTTP(S) citations as a
|
|
111
|
+
deduplicated Markdown source list. When a citation identifies a passage,
|
|
112
|
+
the source includes that exact quoted answer text and its location in the
|
|
113
|
+
original text part. These are passages from the answer, not excerpts from
|
|
114
|
+
the source page. Unresolved citation ranges keep the source link without
|
|
115
|
+
inventing a passage. Results that exceed Pi's output limits are shown as a
|
|
116
|
+
marked preview with a path to the complete answer and sources in a private
|
|
117
|
+
temporary file. The response ID stays visible in the preview and is included
|
|
118
|
+
in the complete report.
|
|
119
|
+
|
|
120
|
+
## Dogfooding Locally
|
|
121
|
+
|
|
122
|
+
Pi transpiles TypeScript extensions with jiti, so it loads `src/index.ts`
|
|
123
|
+
directly. There is no build step: the package ships source.
|
|
124
|
+
|
|
125
|
+
### Option 1: Load It Directly With `pi -e`
|
|
126
|
+
|
|
127
|
+
This is the fastest way to test a local checkout.
|
|
128
|
+
|
|
129
|
+
From the repo root:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pi --no-extensions --no-skills -e ./src/index.ts
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If the extension loads successfully, Pi will have:
|
|
136
|
+
|
|
137
|
+
- the `web_search` tool
|
|
138
|
+
- the `web_fetch` tool
|
|
139
|
+
- `parallel` listed under `/login`
|
|
140
|
+
- the `parallel-login` status command
|
|
141
|
+
- the `web_research` tool
|
|
142
|
+
- per-session Parallel `session_id` reuse inside that Pi session
|
|
143
|
+
|
|
144
|
+
### Option 2: Symlink It Into Pi Extensions
|
|
145
|
+
|
|
146
|
+
This is better if you want Pi to auto-discover it and support `/reload`.
|
|
147
|
+
|
|
148
|
+
Then symlink the package directory into Pi's global extensions folder:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
mkdir -p ~/.pi/agent/extensions
|
|
152
|
+
ln -s \
|
|
153
|
+
"$PWD" \
|
|
154
|
+
~/.pi/agent/extensions/normful-parallel-pi-extension
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Then start Pi normally:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
pi
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
After code changes, run `/reload` inside Pi.
|
|
164
|
+
|
|
165
|
+
## Local Auth Testing
|
|
166
|
+
|
|
167
|
+
### Use Stored Pi Auth
|
|
168
|
+
|
|
169
|
+
Inside Pi, run:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
/login parallel
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
That opens the browser for Parallel OAuth. On success, Pi stores the API key in
|
|
176
|
+
its auth store under `parallel`. Run `/parallel-login` to see the current status,
|
|
177
|
+
and run `/logout` and select Parallel to remove the stored credential.
|
|
178
|
+
|
|
179
|
+
### Use Environment Variable Instead
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
export PARALLEL_API_KEY=your_key_here
|
|
183
|
+
pi --no-extensions --no-skills -e ./src/index.ts
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Note: stored Pi auth is preferred over `PARALLEL_API_KEY` if both exist.
|
|
187
|
+
|
|
188
|
+
### Override The OAuth Platform URL
|
|
189
|
+
|
|
190
|
+
For local or staging OAuth testing, set `PARALLEL_PLATFORM_URL` before starting Pi:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
export PARALLEL_PLATFORM_URL=https://your-platform-host
|
|
194
|
+
pi --no-extensions --no-skills -e ./src/index.ts
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This changes the browser login endpoints used by `/login parallel`.
|
|
198
|
+
|
|
199
|
+
### Override The API Base URL
|
|
200
|
+
|
|
201
|
+
`PARALLEL_BASE_URL` redirects every Parallel API call the tools make — search,
|
|
202
|
+
extract and research all follow it, so they can be pointed at a staging or local
|
|
203
|
+
host together:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
export PARALLEL_BASE_URL=https://your-api-host
|
|
207
|
+
pi --no-extensions --no-skills -e ./src/index.ts
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The value is an **origin**, not a full URL: the `/v1/search`, `/v1/extract` and
|
|
211
|
+
`/v1/responses` paths are appended to it, and a trailing slash is tolerated.
|
|
212
|
+
Unset it to use `https://api.parallel.ai`.
|
|
213
|
+
|
|
214
|
+
This is separate from `PARALLEL_PLATFORM_URL`, which only affects the OAuth
|
|
215
|
+
login flow (that host is `platform.parallel.ai`, not `api.parallel.ai`).
|
|
216
|
+
|
|
217
|
+
## Quick Smoke Test
|
|
218
|
+
|
|
219
|
+
Once Pi is running with the extension loaded, ask something that should force web usage, for example:
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
Search the web for the latest Parallel docs on OAuth and summarize them.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Or ask Pi to call the tool explicitly.
|
|
226
|
+
|
|
227
|
+
`web_search` requires `search_queries`.
|
|
228
|
+
|
|
229
|
+
`web_fetch` accepts multiple URLs in a single call, so the agent can batch extraction work instead of parallelizing many single-URL requests.
|
|
230
|
+
|
|
231
|
+
## Dev Loop
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npm test
|
|
235
|
+
npm run typecheck
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Notes
|
|
239
|
+
|
|
240
|
+
- Search and Fetch use the `parallel-web` TypeScript SDK; Research calls the
|
|
241
|
+
Responses endpoint directly.
|
|
242
|
+
- Search requests use Parallel SDK `fast` mode.
|
|
243
|
+
- Search requests include `client_model` when Pi has an active model selected.
|
|
244
|
+
- Search and extract requests reuse a generated `session_id` for the life of the current Pi session.
|
|
245
|
+
- The login flow tries to open your browser automatically.
|
|
246
|
+
- If automatic callback capture does not complete, the login dialog asks you to paste the callback URL.
|
|
247
|
+
- Credential storage is entirely Pi's; the extension only reads the resolved key
|
|
248
|
+
through `ctx.modelRegistry.getApiKeyForProvider("parallel")`.
|
|
249
|
+
- Research requests do not reuse the Search/Extract `session_id`.
|
|
250
|
+
- Skill suppression inside the extension is prompt-level only. If you want a clean dogfooding session without your usual skills list, start Pi with `--no-skills`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@normful/parallel-web-pi-extension",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Add Parallel web search, fetch, and research tools to your pi agent",
|
|
5
|
+
"author": "Norman Sue",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"pi": {
|
|
9
|
+
"image": "https://assets.parallel.ai/white-parallel-avatar-540.png",
|
|
10
|
+
"extensions": [
|
|
11
|
+
"./src/index.ts"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"!src/**/*.test.ts",
|
|
17
|
+
"package.json",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"parallel-web": "1.3.0",
|
|
22
|
+
"typebox": "^1.1.37"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@earendil-works/pi-coding-agent": ">=0.83.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@earendil-works/pi-ai": ">=0.83.0",
|
|
29
|
+
"@types/node": "^24.0.0",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
31
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
32
|
+
"@vitest/coverage-v8": "^5.0.4",
|
|
33
|
+
"eslint": "^8.54.0",
|
|
34
|
+
"prettier": "^3.1.0",
|
|
35
|
+
"typescript": "^5.3.2",
|
|
36
|
+
"vitest": "^5.0.4"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"coverage": "vitest run --coverage",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"lint": "eslint .",
|
|
43
|
+
"lint:fix": "eslint . --fix",
|
|
44
|
+
"format": "prettier --write .",
|
|
45
|
+
"format:check": "prettier --check ."
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"pi-package",
|
|
49
|
+
"pi.dev",
|
|
50
|
+
"pi agent",
|
|
51
|
+
"extension",
|
|
52
|
+
"parallel",
|
|
53
|
+
"research",
|
|
54
|
+
"web",
|
|
55
|
+
"search",
|
|
56
|
+
"fetch",
|
|
57
|
+
"ai"
|
|
58
|
+
],
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/normful/parallel-web-pi-extension-fork.git"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|