@lincoln504/pi-research 1.0.2 → 1.0.3
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 +1 -1
- package/dist/cli.mjs +53 -17
- package/docs/AGENT-SKILL.md +16 -3
- package/docs/CONFIGURATION.md +3 -3
- package/docs/SDK.md +8 -1
- package/package.json +1 -1
- package/skills/pi-research/README.md +2 -2
- package/skills/pi-research/SKILL.md +6 -3
- package/skills/pi-research/references/configuration.md +7 -4
- package/skills/pi-research/scripts/run.mjs +3 -2
- package/src/cli.ts +48 -13
- package/src/research-config.ts +14 -1
- package/src/sdk.ts +35 -13
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ pi install npm:@lincoln504/pi-research
|
|
|
63
63
|
|
|
64
64
|
See [Agent skill](docs/AGENT-SKILL.md) or [SDK](docs/SDK.md) for standalone (no pi extension) installation.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
The pi extension works out of the box — it runs on your pi session's model and pi's own configuration. Standalone use (agent skill / CLI / SDK) requires a configured model: set `PI_RESEARCH_MODEL` (e.g. `openai/gpt-4o`) as an environment variable or in `~/.pi/research/config.env`, plus `PI_RESEARCH_API_KEY` if you don't use pi. See [Configuration](docs/CONFIGURATION.md).
|
|
67
67
|
|
|
68
68
|
The first install pulls the stealth browser engine, which takes a few minutes.
|
|
69
69
|
|
package/dist/cli.mjs
CHANGED
|
@@ -22000,14 +22000,15 @@ async function _doInit(options = {}) {
|
|
|
22000
22000
|
}
|
|
22001
22001
|
globalApiKey = options.apiKey || process.env["PI_RESEARCH_API_KEY"];
|
|
22002
22002
|
let parsedProvider = options.provider || process.env["PI_RESEARCH_PROVIDER"];
|
|
22003
|
-
|
|
22004
|
-
|
|
22005
|
-
|
|
22003
|
+
const effectiveModel = options.model ?? globalConfig.RESEARCH_MODEL;
|
|
22004
|
+
if (!parsedProvider && effectiveModel) {
|
|
22005
|
+
if (typeof effectiveModel === "string") {
|
|
22006
|
+
const slashIdx = effectiveModel.indexOf("/");
|
|
22006
22007
|
if (slashIdx > 0) {
|
|
22007
|
-
parsedProvider =
|
|
22008
|
+
parsedProvider = effectiveModel.slice(0, slashIdx);
|
|
22008
22009
|
}
|
|
22009
|
-
} else if (
|
|
22010
|
-
parsedProvider =
|
|
22010
|
+
} else if (effectiveModel.provider) {
|
|
22011
|
+
parsedProvider = effectiveModel.provider;
|
|
22011
22012
|
}
|
|
22012
22013
|
}
|
|
22013
22014
|
if (globalApiKey && !parsedProvider) {
|
|
@@ -22015,7 +22016,16 @@ async function _doInit(options = {}) {
|
|
|
22015
22016
|
}
|
|
22016
22017
|
globalRegistry = buildModelRegistry(globalApiKey, parsedProvider);
|
|
22017
22018
|
try {
|
|
22018
|
-
|
|
22019
|
+
if (effectiveModel && typeof effectiveModel === "object" && effectiveModel.id) {
|
|
22020
|
+
globalModel = effectiveModel;
|
|
22021
|
+
} else {
|
|
22022
|
+
globalModel = resolveModel(
|
|
22023
|
+
globalRegistry,
|
|
22024
|
+
typeof effectiveModel === "string" ? effectiveModel : void 0,
|
|
22025
|
+
parsedProvider,
|
|
22026
|
+
globalApiKey
|
|
22027
|
+
);
|
|
22028
|
+
}
|
|
22019
22029
|
globalContainer = getServiceContainer();
|
|
22020
22030
|
registerCoreServices(globalContainer);
|
|
22021
22031
|
registerInfrastructureServices(globalContainer);
|
|
@@ -22630,6 +22640,18 @@ function detectCredentials() {
|
|
|
22630
22640
|
};
|
|
22631
22641
|
}
|
|
22632
22642
|
if (piAuthPresent) {
|
|
22643
|
+
if (!model) {
|
|
22644
|
+
return {
|
|
22645
|
+
source: "pi-config",
|
|
22646
|
+
apiKeyConfigured: true,
|
|
22647
|
+
provider,
|
|
22648
|
+
model,
|
|
22649
|
+
modelFrom,
|
|
22650
|
+
piAuthPresent,
|
|
22651
|
+
piModelsPresent,
|
|
22652
|
+
problem: 'pi credentials were found (auth.json), but no research model is configured. The standalone CLI / agent skill run only on an explicitly configured model \u2014 they do not follow the model selected inside the pi extension. Set PI_RESEARCH_MODEL to a "provider/model-id" (in the environment, or in config.env / cli.env below).'
|
|
22653
|
+
};
|
|
22654
|
+
}
|
|
22633
22655
|
return {
|
|
22634
22656
|
source: "pi-config",
|
|
22635
22657
|
apiKeyConfigured: true,
|
|
@@ -22659,14 +22681,14 @@ function configBlock(det, extraNote) {
|
|
|
22659
22681
|
lines.push(` \u2022 base config file: ${paths.configEnv}`);
|
|
22660
22682
|
lines.push(` \u2022 cli overlay: ${paths.cliIfaceEnv} (optional; overrides base for this CLI / agent skill)`);
|
|
22661
22683
|
lines.push(` \u2022 env vars: PI_RESEARCH_API_KEY / PI_RESEARCH_PROVIDER / PI_RESEARCH_MODEL`);
|
|
22662
|
-
lines.push(` \u2022 pi
|
|
22663
|
-
lines.push(` \u2022 pi models:
|
|
22684
|
+
lines.push(` \u2022 pi config (keys): ${paths.piAuth}`);
|
|
22685
|
+
lines.push(` \u2022 pi config (models): ${paths.piModels}`);
|
|
22664
22686
|
lines.push("");
|
|
22665
22687
|
lines.push("Detected:");
|
|
22666
22688
|
lines.push(` \u2022 credential source: ${det.source}`);
|
|
22667
22689
|
lines.push(` \u2022 api key configured: ${det.apiKeyConfigured}`);
|
|
22668
|
-
lines.push(` \u2022 provider: ${det.provider ?? "(unset)"}`);
|
|
22669
|
-
lines.push(` \u2022 model: ${det.model
|
|
22690
|
+
lines.push(` \u2022 provider: ${det.provider ?? "(unset \u2014 inferred from a provider/model-id model)"}`);
|
|
22691
|
+
lines.push(` \u2022 model: ${det.model ? `${det.model} [from: ${det.modelFrom}]` : "(not set \u2014 set PI_RESEARCH_MODEL, required)"}`);
|
|
22670
22692
|
lines.push(` \u2022 pi auth.json: ${det.piAuthPresent ? "present" : "absent"}`);
|
|
22671
22693
|
lines.push(` \u2022 pi models.json: ${det.piModelsPresent ? "present" : "absent"}`);
|
|
22672
22694
|
if (extraNote) lines.push(` \u2022 note: ${extraNote}`);
|
|
@@ -22923,8 +22945,9 @@ uninstall: ${BINARY_NAME} skill uninstall
|
|
|
22923
22945
|
} catch (err) {
|
|
22924
22946
|
return reportError(err, "skill install", s.json);
|
|
22925
22947
|
}
|
|
22948
|
+
const skillModel = process.env["PI_RESEARCH_MODEL"] ?? getConfig(process.cwd(), "cli").RESEARCH_MODEL;
|
|
22926
22949
|
if (s.json) {
|
|
22927
|
-
toStdout(pretty({ command: "skill", action: "install", dryRun: !!s.dryRun, results: results2 }));
|
|
22950
|
+
toStdout(pretty({ command: "skill", action: "install", dryRun: !!s.dryRun, results: results2, modelConfigured: Boolean(skillModel) }));
|
|
22928
22951
|
} else {
|
|
22929
22952
|
toStdout(`pi-research agent skill \u2014 ${s.dryRun ? "install (dry run)" : "install"}
|
|
22930
22953
|
|
|
@@ -22934,6 +22957,15 @@ uninstall: ${BINARY_NAME} skill uninstall
|
|
|
22934
22957
|
toStdout(`
|
|
22935
22958
|
The skill activates automatically \u2014 ask the agent to research something.
|
|
22936
22959
|
`);
|
|
22960
|
+
if (!skillModel) {
|
|
22961
|
+
toStdout(
|
|
22962
|
+
`
|
|
22963
|
+
Required: set PI_RESEARCH_MODEL=provider/model-id in ${resolvedConfigPaths().configEnv}
|
|
22964
|
+
(or as an env var) \u2014 the skill runs only on this configured model, not your pi
|
|
22965
|
+
session model. Verify with: ${BINARY_NAME} status
|
|
22966
|
+
`
|
|
22967
|
+
);
|
|
22968
|
+
}
|
|
22937
22969
|
}
|
|
22938
22970
|
return results2.some((r) => r.status === "error") ? EXIT.SOFTWARE : EXIT.OK;
|
|
22939
22971
|
}
|
|
@@ -23091,11 +23123,15 @@ COMMANDS
|
|
|
23091
23123
|
CONFIGURE
|
|
23092
23124
|
Credentials are resolved in this order (first match wins):
|
|
23093
23125
|
|
|
23094
|
-
env vars:
|
|
23095
|
-
cli overlay:
|
|
23096
|
-
base config:
|
|
23097
|
-
pi
|
|
23098
|
-
pi models:
|
|
23126
|
+
env vars: PI_RESEARCH_API_KEY PI_RESEARCH_PROVIDER PI_RESEARCH_MODEL
|
|
23127
|
+
cli overlay: ${p.cliIfaceEnv} (optional; this CLI / agent skill only)
|
|
23128
|
+
base config: ${p.configEnv}
|
|
23129
|
+
pi config (keys): ${p.piAuth}
|
|
23130
|
+
pi config (models): ${p.piModels}
|
|
23131
|
+
|
|
23132
|
+
A model is REQUIRED: set PI_RESEARCH_MODEL to a "provider/model-id". This CLI and
|
|
23133
|
+
the agent skill run only on that configured model \u2014 they do not follow the model
|
|
23134
|
+
selected inside the pi extension.
|
|
23099
23135
|
|
|
23100
23136
|
The pi extension has its own optional overlay file:
|
|
23101
23137
|
pi extension: ${p.piIfaceEnv}
|
package/docs/AGENT-SKILL.md
CHANGED
|
@@ -10,7 +10,8 @@ pi-research software.
|
|
|
10
10
|
Already running the `pi` extension (`pi install npm:@lincoln504/pi-research`)? You
|
|
11
11
|
already have the engine — install the skill into your other agents with
|
|
12
12
|
`/research-config` → Install in External Agents (see [Installation flow](#installation-flow))
|
|
13
|
-
and skip the
|
|
13
|
+
and skip the install commands below. The model step still applies to you: the
|
|
14
|
+
skill runs on its own configured `PI_RESEARCH_MODEL`, not your pi session's model.
|
|
14
15
|
|
|
15
16
|
For standalone use without pi, install the engine globally, then link the skill into
|
|
16
17
|
every coding agent detected on this machine:
|
|
@@ -24,6 +25,18 @@ pi-research skill install # link the skill into Claude, Codex, Op
|
|
|
24
25
|
different skill in the slot, and records what it created so `pi-research skill uninstall`
|
|
25
26
|
removes exactly that. Run `pi-research skill status` to see where it is installed.
|
|
26
27
|
|
|
28
|
+
Then configure the model research runs on — the skill and standalone CLI use only
|
|
29
|
+
this explicitly configured model (they never follow the model selected inside the
|
|
30
|
+
pi extension) and refuse to start without one:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
# ~/.pi/research/config.env (or export as an env var)
|
|
34
|
+
PI_RESEARCH_MODEL=provider/model-id
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If you use `pi`, the API key comes from your pi configuration (`~/.pi/agent/auth.json`) automatically; otherwise
|
|
38
|
+
also set `PI_RESEARCH_API_KEY` (same file or env var). See [Configuration](CONFIGURATION.md).
|
|
39
|
+
|
|
27
40
|
On Windows, run `pi-research` from `cmd` or use `pi-research.cmd`: PowerShell's default
|
|
28
41
|
execution policy (`Restricted`) blocks npm's `.ps1` shims ("running scripts is
|
|
29
42
|
disabled"); or run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once.
|
|
@@ -114,8 +127,8 @@ Manual. Symlink the directory into any agent's skills folder yourself:
|
|
|
114
127
|
### Prerequisites
|
|
115
128
|
|
|
116
129
|
- Node.js >= 22.19.0
|
|
117
|
-
- `pi-research` installed where the launcher can find it, plus a model
|
|
118
|
-
See [Configuration](CONFIGURATION.md).
|
|
130
|
+
- `pi-research` installed where the launcher can find it, plus a configured model
|
|
131
|
+
(`PI_RESEARCH_MODEL`) + API key. See [Configuration](CONFIGURATION.md).
|
|
119
132
|
|
|
120
133
|
```bash
|
|
121
134
|
npm install -g @lincoln504/pi-research
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -75,7 +75,7 @@ Research
|
|
|
75
75
|
| `PI_RESEARCH_RETRY_DELAY_MS` | `2000` | 100–10000 | Base delay between retries. |
|
|
76
76
|
| `PI_RESEARCH_WORKER_THREADS` | `4` | 1–10 | Browser worker processes. Higher = more throughput, more CPU/RAM. |
|
|
77
77
|
| `PI_RESEARCH_WORKER_CONCURRENCY` | `2` | 1–10 | Tasks per worker process. |
|
|
78
|
-
| `PI_RESEARCH_MODEL` | _(session model)_ | — |
|
|
78
|
+
| `PI_RESEARCH_MODEL` | _(pi: session model; CLI/skill: required)_ | — | The model research runs on. **Required for the standalone CLI / agent skill** — they use only this configured model (never the model selected inside the pi extension) and refuse to start without one. On the SDK it selects the session model when no `model` option is given. In the pi extension it overrides researcher sub-agents and knowledge synthesis, while the coordinator and evaluator keep using the session model. Accepts `provider/id` or a bare model id. |
|
|
79
79
|
| `PI_RESEARCH_DISABLED_TOOLS` | _(none)_ | — | Comma-separated research tools to disable for a run (`search`, `scrape`, `security_search`, `stackexchange`, `youtube_transcript`, `grep`). Removed from every researcher's toolset and named in the coordinator/evaluator prompt. |
|
|
80
80
|
| `PI_RESEARCH_REPORT_EXPORT_ENABLED` (TUI) | `false` | — | Front-ends write a Markdown report to disk and surface its path. |
|
|
81
81
|
| `PI_RESEARCH_REPORT_EXPORT_DIR` | _(smart cwd)_ | — | Pin exported reports to a fixed directory, bypassing the cwd-relative resolution. Useful for the agent skill, which runs from the host agent's arbitrary directory. |
|
|
@@ -128,11 +128,11 @@ See the [knowledge store doc](KNOWLEDGE-STORE.md) for what each value does.
|
|
|
128
128
|
| `PI_RESEARCH_EMBEDDING_MODEL_INIT_TIMEOUT_MS` | `300000` | 10000–600000 | Embedding-model initialization timeout (first-time download can be slow). |
|
|
129
129
|
| `PI_RESEARCH_WEBGPU_REPROBE` | _(unset)_ | — | Set `1` to discard the cached WebGPU-viability verdict and probe again on next use. |
|
|
130
130
|
|
|
131
|
-
API keys
|
|
131
|
+
API keys
|
|
132
132
|
|
|
133
133
|
| Variable | Description |
|
|
134
134
|
|----------|-------------|
|
|
135
|
-
| `PI_RESEARCH_API_KEY` / `PI_RESEARCH_PROVIDER` | Explicit LLM credentials for SDK / CLI mode (not needed when
|
|
135
|
+
| `PI_RESEARCH_API_KEY` / `PI_RESEARCH_PROVIDER` | Explicit LLM credentials for SDK / CLI mode (not needed when pi's configuration — `~/.pi/agent/auth.json` — supplies the key). On the CLI / agent skill both can also live in `config.env` / `cli.env`. The provider is required alongside the key, or inferred from a `provider/model-id` `PI_RESEARCH_MODEL`. |
|
|
136
136
|
| `STACKEXCHANGE_API_KEY` | Raises the Stack Exchange tool's limit from 300/day to 10,000/day. Obtain at <https://stackapps.com/apps/oauth>. |
|
|
137
137
|
| `GITHUB_TOKEN` | Raises the security tool's GitHub Advisory limit from 60/hr to 5000/hr (any default-scope token). |
|
|
138
138
|
| `NVD_API_KEY` | Raises the security tool's NVD limit ~10× and tightens request spacing. Request at <https://nvd.nist.gov/developers/request-an-api-key>. Recommended when using severity-filtered security searches: those issue a second (CVSS v2) NVD query to catch v2-only CVEs, which roughly doubles request time against the 6 s/request unauthenticated throttle. |
|
package/docs/SDK.md
CHANGED
|
@@ -13,6 +13,13 @@ run the `pi` extension, which keeps its own private copy your scripts can't impo
|
|
|
13
13
|
npm install @lincoln504/pi-research
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Then pick the model: pass `model` to `initResearchSDK`, or set `PI_RESEARCH_MODEL`
|
|
17
|
+
(env or `~/.pi/research/config.env`). The SDK never follows the model selected
|
|
18
|
+
inside the pi extension; only when neither is set does it fall back to the first
|
|
19
|
+
available model in your pi registry. The API key comes from your pi
|
|
20
|
+
configuration (`~/.pi/agent/auth.json`) automatically, or from the `apiKey`
|
|
21
|
+
option / `PI_RESEARCH_API_KEY` env var.
|
|
22
|
+
|
|
16
23
|
`src/sdk.ts` is a library for scripts, CI, and custom tooling. It is configured
|
|
17
24
|
from code, not from a global overlay file — there is no `sdk.env`. It reads the
|
|
18
25
|
base `~/.pi/research/config.env` as a baseline, and everything is
|
|
@@ -83,7 +90,7 @@ extension and the CLI / agent skill do it when `PI_RESEARCH_REPORT_EXPORT_ENABLE
|
|
|
83
90
|
|
|
84
91
|
| Option | Description |
|
|
85
92
|
|--------|-------------|
|
|
86
|
-
| `model` | `"provider/id"` string or a `Model` object. Omit to use the first available pi model. |
|
|
93
|
+
| `model` | `"provider/id"` string or a `Model` object. Omit to use the configured `PI_RESEARCH_MODEL`; only when neither is set does the SDK fall back to the first available pi model. |
|
|
87
94
|
| `apiKey` / `provider` | Explicit credentials (provider required with apiKey). |
|
|
88
95
|
| `config` | `Partial<Config>` overrides, applied over the base/defaults. |
|
|
89
96
|
| `ignoreGlobalConfig` | Skip `config.env` entirely — defaults + `process.env` + `config` only. |
|
package/package.json
CHANGED
|
@@ -39,8 +39,8 @@ model/key is missing.
|
|
|
39
39
|
### Prerequisites
|
|
40
40
|
|
|
41
41
|
- Node.js >= 22.19.0
|
|
42
|
-
- `pi-research` installed somewhere the launcher can find it, and a
|
|
43
|
-
API key
|
|
42
|
+
- `pi-research` installed somewhere the launcher can find it, and a configured
|
|
43
|
+
model (`PI_RESEARCH_MODEL`) + API key. See [`references/configuration.md`](references/configuration.md).
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
npm install -g @lincoln504/pi-research
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: pi-research
|
|
3
3
|
description: "Multi-agent web research for any coding agent. Use for anything requiring current information from the internet — news, trends, product/service/company facts, statistics, people, places, events, APIs, library behavior, or 'what is X / how does X work' questions. Also use to search a local knowledge store of previously researched findings before doing live research. Powered by the pi-research engine (search, stealth scraping, security databases, Stack Exchange). Not for reading local files, running project commands, or analyzing this repository's own source."
|
|
4
4
|
license: MIT
|
|
5
|
-
metadata: { "author": "Lincoln Deen", "version": "1.0.
|
|
5
|
+
metadata: { "author": "Lincoln Deen", "version": "1.0.3", "package": "@lincoln504/pi-research", "engine": "pi-research-sdk", "openclaw": { "requires": { "bins": ["node"] } } }
|
|
6
6
|
allowed-tools: Bash(node:*)
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -91,10 +91,13 @@ On exit 78 the engine prints exact configure locations to stderr — relay verba
|
|
|
91
91
|
```
|
|
92
92
|
config file: ~/.pi/research/config.env
|
|
93
93
|
env vars: PI_RESEARCH_API_KEY PI_RESEARCH_PROVIDER PI_RESEARCH_MODEL
|
|
94
|
-
pi
|
|
95
|
-
pi models:
|
|
94
|
+
pi config (keys): ~/.pi/agent/auth.json (supplies the API key only)
|
|
95
|
+
pi config (models): ~/.pi/agent/models.json
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
+
`PI_RESEARCH_MODEL` (a `provider/model-id`) is always required — pi's configuration
|
|
99
|
+
supplies only the key, and the skill never uses the model selected inside the pi extension.
|
|
100
|
+
|
|
98
101
|
Run `status` for the resolved paths on this machine. Full reference:
|
|
99
102
|
[`references/configuration.md`](references/configuration.md).
|
|
100
103
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
## Configuration
|
|
2
2
|
|
|
3
|
-
The skill drives the **pi-research** engine, which needs
|
|
3
|
+
The skill drives the **pi-research** engine, which needs an explicitly configured
|
|
4
|
+
model (`PI_RESEARCH_MODEL`) + API key — it runs only on that configured model and
|
|
5
|
+
never follows the model selected inside the pi extension.
|
|
4
6
|
Run `node "<SKILL_DIR>/scripts/run.mjs" status` to print what's detected and where
|
|
5
7
|
to configure (no research runs).
|
|
6
8
|
|
|
@@ -13,7 +15,8 @@ to configure (no research runs).
|
|
|
13
15
|
export PI_RESEARCH_MODEL=openai/gpt-4o # provider/model-id
|
|
14
16
|
```
|
|
15
17
|
2. **Global config** `~/.pi/research/config.env` (same KEY=VALUE keys; read at startup).
|
|
16
|
-
3. **pi
|
|
18
|
+
3. **pi configuration** (if you use `pi`): the API key comes from `~/.pi/agent/auth.json`
|
|
19
|
+
automatically — `PI_RESEARCH_MODEL` must still be set (env or `config.env`).
|
|
17
20
|
|
|
18
21
|
Real env vars always win. Optional CLI-only overlay `~/.pi/research/cli.env` layers
|
|
19
22
|
over `config.env` for the CLI only. Precedence:
|
|
@@ -23,7 +26,7 @@ over `config.env` for the CLI only. Precedence:
|
|
|
23
26
|
|
|
24
27
|
| Variable | Default | Description |
|
|
25
28
|
|----------|---------|-------------|
|
|
26
|
-
| `PI_RESEARCH_MODEL` |
|
|
29
|
+
| `PI_RESEARCH_MODEL` | _(required)_ | The `provider/model-id` all research runs on. |
|
|
27
30
|
| `PI_RESEARCH_DEFAULT_RESEARCH_DEPTH` | `1` | Default depth (1–3) when `--depth` omitted. |
|
|
28
31
|
| `PI_RESEARCH_MAX_RESEARCHERS` | `3` | Parallel researchers (1–5). |
|
|
29
32
|
| `PI_RESEARCH_TIMEOUT_MS` | `300000` | Per-researcher timeout (180000–1800000). |
|
|
@@ -70,7 +73,7 @@ model/key; message lists the fix) · `70` runtime error (network/provider/intern
|
|
|
70
73
|
`export PI_RESEARCH_BIN=/path/to/pi-research/dist/cli.mjs` (exact CLI entry;
|
|
71
74
|
checked first — also the escape hatch for unusual Windows shim layouts).
|
|
72
75
|
- **"No model or API key" (78 from engine):** set the three env vars (or config /
|
|
73
|
-
pi
|
|
76
|
+
pi's configuration), then re-run `status`.
|
|
74
77
|
- **Rate limit (70):** provider returned 429 — wait and retry.
|
|
75
78
|
- **GPU/embedding errors:** set `PI_RESEARCH_EMBEDDING_DEVICE=cpu` (headless/no-GPU).
|
|
76
79
|
|
|
@@ -139,10 +139,11 @@ function notInstalled() {
|
|
|
139
139
|
" # or, with pi: pi install npm:@lincoln504/pi-research",
|
|
140
140
|
" # or point at a copy: export PI_RESEARCH_PATH=/path/to/pi-research",
|
|
141
141
|
"",
|
|
142
|
-
"After installing, configure
|
|
142
|
+
"After installing, configure the model (PI_RESEARCH_MODEL is required) + API key.",
|
|
143
|
+
"Locations:",
|
|
143
144
|
` \u2022 env vars: PI_RESEARCH_API_KEY / PI_RESEARCH_PROVIDER / PI_RESEARCH_MODEL`,
|
|
144
145
|
` \u2022 global config file: ${join(home, ".pi", "research", "config.env")}`,
|
|
145
|
-
` \u2022 pi
|
|
146
|
+
` \u2022 pi config (keys): ${join(home, ".pi", "agent", "auth.json")} (supplies the API key only)`,
|
|
146
147
|
"",
|
|
147
148
|
"Run `status` once installed to verify detection.",
|
|
148
149
|
""
|
package/src/cli.ts
CHANGED
|
@@ -196,7 +196,7 @@ export interface ResolvedConfigPaths {
|
|
|
196
196
|
cliIfaceEnv: string;
|
|
197
197
|
/** Per-interface overlay for the pi extension (~/.pi/research/pi.env). */
|
|
198
198
|
piIfaceEnv: string;
|
|
199
|
-
/** pi
|
|
199
|
+
/** pi's key file (~/.pi/agent/auth.json), part of pi's configuration. */
|
|
200
200
|
piAuth: string;
|
|
201
201
|
/** pi model definitions (~/.pi/agent/models.json). */
|
|
202
202
|
piModels: string;
|
|
@@ -300,9 +300,29 @@ function detectCredentials(): CredentialDetection {
|
|
|
300
300
|
};
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
// --- pi
|
|
303
|
+
// --- pi configuration path (key from auth.json) -----------------------------
|
|
304
304
|
if (piAuthPresent) {
|
|
305
|
-
//
|
|
305
|
+
// Keys come from auth.json, but the MODEL must be configured explicitly:
|
|
306
|
+
// the standalone CLI / agent skill run only on the configured model — they
|
|
307
|
+
// never follow the model selected inside the pi extension, and silently
|
|
308
|
+
// falling back to the registry's first authed entry picks a model nobody
|
|
309
|
+
// chose. Fail fast here (pre-flight, before any SDK init).
|
|
310
|
+
if (!model) {
|
|
311
|
+
return {
|
|
312
|
+
source: 'pi-config',
|
|
313
|
+
apiKeyConfigured: true,
|
|
314
|
+
provider,
|
|
315
|
+
model,
|
|
316
|
+
modelFrom,
|
|
317
|
+
piAuthPresent,
|
|
318
|
+
piModelsPresent,
|
|
319
|
+
problem:
|
|
320
|
+
'pi credentials were found (auth.json), but no research model is configured. ' +
|
|
321
|
+
'The standalone CLI / agent skill run only on an explicitly configured model — they do not ' +
|
|
322
|
+
'follow the model selected inside the pi extension. Set PI_RESEARCH_MODEL to a ' +
|
|
323
|
+
'"provider/model-id" (in the environment, or in config.env / cli.env below).',
|
|
324
|
+
};
|
|
325
|
+
}
|
|
306
326
|
return {
|
|
307
327
|
source: 'pi-config',
|
|
308
328
|
apiKeyConfigured: true, // key lives in auth.json; SDK reads it
|
|
@@ -342,14 +362,14 @@ function configBlock(det: CredentialDetection, extraNote?: string): string {
|
|
|
342
362
|
lines.push(` • base config file: ${paths.configEnv}`);
|
|
343
363
|
lines.push(` • cli overlay: ${paths.cliIfaceEnv} (optional; overrides base for this CLI / agent skill)`);
|
|
344
364
|
lines.push(` • env vars: PI_RESEARCH_API_KEY / PI_RESEARCH_PROVIDER / PI_RESEARCH_MODEL`);
|
|
345
|
-
lines.push(` • pi
|
|
346
|
-
lines.push(` • pi models:
|
|
365
|
+
lines.push(` • pi config (keys): ${paths.piAuth}`);
|
|
366
|
+
lines.push(` • pi config (models): ${paths.piModels}`);
|
|
347
367
|
lines.push('');
|
|
348
368
|
lines.push('Detected:');
|
|
349
369
|
lines.push(` • credential source: ${det.source}`);
|
|
350
370
|
lines.push(` • api key configured: ${det.apiKeyConfigured}`);
|
|
351
|
-
lines.push(` • provider: ${det.provider ?? '(unset)'}`);
|
|
352
|
-
lines.push(` • model: ${det.model
|
|
371
|
+
lines.push(` • provider: ${det.provider ?? '(unset — inferred from a provider/model-id model)'}`);
|
|
372
|
+
lines.push(` • model: ${det.model ? `${det.model} [from: ${det.modelFrom}]` : '(not set — set PI_RESEARCH_MODEL, required)'}`);
|
|
353
373
|
lines.push(` • pi auth.json: ${det.piAuthPresent ? 'present' : 'absent'}`);
|
|
354
374
|
lines.push(` • pi models.json: ${det.piModelsPresent ? 'present' : 'absent'}`);
|
|
355
375
|
if (extraNote) lines.push(` • note: ${extraNote}`);
|
|
@@ -657,12 +677,23 @@ async function cmdSkill(s: NonNullable<ParsedArgs['skill']>): Promise<number> {
|
|
|
657
677
|
} catch (err) {
|
|
658
678
|
return reportError(err, 'skill install', s.json);
|
|
659
679
|
}
|
|
680
|
+
// The skill runs only on an explicitly configured model — if none is set yet,
|
|
681
|
+
// say so right here, at the moment of install (mirrors the TUI install action).
|
|
682
|
+
const skillModel =
|
|
683
|
+
process.env['PI_RESEARCH_MODEL'] ?? getConfig(process.cwd(), 'cli').RESEARCH_MODEL;
|
|
660
684
|
if (s.json) {
|
|
661
|
-
toStdout(pretty({ command: 'skill', action: 'install', dryRun: !!s.dryRun, results }));
|
|
685
|
+
toStdout(pretty({ command: 'skill', action: 'install', dryRun: !!s.dryRun, results, modelConfigured: Boolean(skillModel) }));
|
|
662
686
|
} else {
|
|
663
687
|
toStdout(`pi-research agent skill — ${s.dryRun ? 'install (dry run)' : 'install'}\n\n`);
|
|
664
688
|
for (const r of results) toStdout(` ${r.tool.padEnd(10)} ${describeInstall(r)}\n`);
|
|
665
689
|
toStdout(`\nThe skill activates automatically — ask the agent to research something.\n`);
|
|
690
|
+
if (!skillModel) {
|
|
691
|
+
toStdout(
|
|
692
|
+
`\nRequired: set PI_RESEARCH_MODEL=provider/model-id in ${resolvedConfigPaths().configEnv}\n` +
|
|
693
|
+
`(or as an env var) — the skill runs only on this configured model, not your pi\n` +
|
|
694
|
+
`session model. Verify with: ${BINARY_NAME} status\n`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
666
697
|
}
|
|
667
698
|
return results.some((r) => r.status === 'error') ? EXIT.SOFTWARE : EXIT.OK;
|
|
668
699
|
}
|
|
@@ -842,11 +873,15 @@ COMMANDS
|
|
|
842
873
|
CONFIGURE
|
|
843
874
|
Credentials are resolved in this order (first match wins):
|
|
844
875
|
|
|
845
|
-
env vars:
|
|
846
|
-
cli overlay:
|
|
847
|
-
base config:
|
|
848
|
-
pi
|
|
849
|
-
pi models:
|
|
876
|
+
env vars: PI_RESEARCH_API_KEY PI_RESEARCH_PROVIDER PI_RESEARCH_MODEL
|
|
877
|
+
cli overlay: ${p.cliIfaceEnv} (optional; this CLI / agent skill only)
|
|
878
|
+
base config: ${p.configEnv}
|
|
879
|
+
pi config (keys): ${p.piAuth}
|
|
880
|
+
pi config (models): ${p.piModels}
|
|
881
|
+
|
|
882
|
+
A model is REQUIRED: set PI_RESEARCH_MODEL to a "provider/model-id". This CLI and
|
|
883
|
+
the agent skill run only on that configured model — they do not follow the model
|
|
884
|
+
selected inside the pi extension.
|
|
850
885
|
|
|
851
886
|
The pi extension has its own optional overlay file:
|
|
852
887
|
pi extension: ${p.piIfaceEnv}
|
package/src/research-config.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from '@earendil-works/pi-tui';
|
|
24
24
|
import { setInteractiveTuiActive, initGlobalTuiController } from './tui/tui-controller.ts';
|
|
25
25
|
import { normalizeSessionId } from './orchestration/session-state.ts';
|
|
26
|
-
import { getConfig, saveConfig, resetConfig, getDbDir } from './config.ts';
|
|
26
|
+
import { getConfig, saveConfig, resetConfig, getDbDir, getGlobalEnvFilePath } from './config.ts';
|
|
27
27
|
import { healthRegistry } from './healthcheck/index.ts';
|
|
28
28
|
import { getService, clearService, tryGetServiceContainerFromCtx } from './core/service-registry.ts';
|
|
29
29
|
import { ServiceNames, IKnowledgeStoreService } from './core/service-interfaces.ts';
|
|
@@ -648,6 +648,19 @@ async function installSkillAction(ctx: ExtensionContext, pi: ExtensionAPI): Prom
|
|
|
648
648
|
}
|
|
649
649
|
lines.push('', 'The skill activates automatically — just ask the agent to pi-research something.');
|
|
650
650
|
|
|
651
|
+
// The skill runs only on an explicitly configured model (it never follows the
|
|
652
|
+
// pi session model) — if none is configured yet, say so right here, at the
|
|
653
|
+
// moment of install, mirroring the CLI's `skill install` output.
|
|
654
|
+
const skillModel = process.env['PI_RESEARCH_MODEL'] ?? getConfig(ctx.cwd, 'cli').RESEARCH_MODEL;
|
|
655
|
+
if (!skillModel) {
|
|
656
|
+
lines.push(
|
|
657
|
+
'',
|
|
658
|
+
'**Required:** set `PI_RESEARCH_MODEL=provider/model-id` in ' +
|
|
659
|
+
`\`${getGlobalEnvFilePath()}\` (or as an env var) — the skill runs only on ` +
|
|
660
|
+
'this configured model, not your pi session model.'
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
|
|
651
664
|
pi.sendMessage({ customType: 'skill-install-result', content: lines.join('\n'), display: true });
|
|
652
665
|
if (ctx.hasUI) {
|
|
653
666
|
if (ok > 0) ctx.ui.notify(`Skill installed for ${ok} coding agent${ok === 1 ? '' : 's'}.`, 'info');
|
package/src/sdk.ts
CHANGED
|
@@ -144,17 +144,21 @@ function _removeSignalHandlers(): void {
|
|
|
144
144
|
* Options for initializing the Research SDK
|
|
145
145
|
*/
|
|
146
146
|
export interface ResearchSDKOptions {
|
|
147
|
-
/**
|
|
147
|
+
/**
|
|
148
148
|
* The LLM model to use for coordination, planning, and evaluation.
|
|
149
|
-
* If a string, it must match "provider/id" (e.g. "openai/gpt-4o")
|
|
150
|
-
* If omitted, the
|
|
149
|
+
* If a string, it must match "provider/id" (e.g. "openai/gpt-4o"); a Model
|
|
150
|
+
* object is used as-is. If omitted, the configured RESEARCH_MODEL
|
|
151
|
+
* (PI_RESEARCH_MODEL / config.env, or the `config` option) is used; only
|
|
152
|
+
* when neither is set does the SDK fall back to the first available model
|
|
153
|
+
* in pi's configuration. The SDK never follows the model selected
|
|
154
|
+
* interactively inside the pi extension.
|
|
151
155
|
*/
|
|
152
156
|
model?: string | Model<any>;
|
|
153
157
|
|
|
154
158
|
/**
|
|
155
159
|
* Optional explicit API key for the model.
|
|
156
160
|
* If provided, `provider` must also be set.
|
|
157
|
-
* If omitted, pi's
|
|
161
|
+
* If omitted, the key from pi's configuration (~/.pi/agent/auth.json) is used.
|
|
158
162
|
*/
|
|
159
163
|
apiKey?: string;
|
|
160
164
|
|
|
@@ -232,15 +236,18 @@ async function _doInit(options: ResearchSDKOptions = {}): Promise<void> {
|
|
|
232
236
|
globalApiKey = options.apiKey || process.env['PI_RESEARCH_API_KEY'];
|
|
233
237
|
let parsedProvider = options.provider || process.env['PI_RESEARCH_PROVIDER'];
|
|
234
238
|
|
|
235
|
-
// Infer provider from model if not explicitly provided
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
+
// Infer provider from the effective model if not explicitly provided. The
|
|
240
|
+
// effective model is the explicit option first, else the configured
|
|
241
|
+
// RESEARCH_MODEL — the same precedence the resolve below uses.
|
|
242
|
+
const effectiveModel = options.model ?? globalConfig.RESEARCH_MODEL;
|
|
243
|
+
if (!parsedProvider && effectiveModel) {
|
|
244
|
+
if (typeof effectiveModel === 'string') {
|
|
245
|
+
const slashIdx = effectiveModel.indexOf('/');
|
|
239
246
|
if (slashIdx > 0) {
|
|
240
|
-
parsedProvider =
|
|
247
|
+
parsedProvider = effectiveModel.slice(0, slashIdx);
|
|
241
248
|
}
|
|
242
|
-
} else if ((
|
|
243
|
-
parsedProvider = (
|
|
249
|
+
} else if ((effectiveModel as any).provider) {
|
|
250
|
+
parsedProvider = (effectiveModel as any).provider;
|
|
244
251
|
}
|
|
245
252
|
}
|
|
246
253
|
|
|
@@ -252,8 +259,23 @@ async function _doInit(options: ResearchSDKOptions = {}): Promise<void> {
|
|
|
252
259
|
globalRegistry = sharedBuildModelRegistry(globalApiKey, parsedProvider);
|
|
253
260
|
|
|
254
261
|
try {
|
|
255
|
-
// Resolve model
|
|
256
|
-
|
|
262
|
+
// Resolve the model. Precedence: explicit option (a Model object is used
|
|
263
|
+
// as-is; it need not exist in the registry) → configured RESEARCH_MODEL →
|
|
264
|
+
// provider default → registry fallback. Seeding the resolver with the
|
|
265
|
+
// configured model is what keeps the coordinator (which runs on ctx.model)
|
|
266
|
+
// on the SAME model as the researchers/synthesis (which read
|
|
267
|
+
// RESEARCH_MODEL themselves) — without it a configured model would govern
|
|
268
|
+
// only the sub-agents and planning would silently run on the fallback.
|
|
269
|
+
if (effectiveModel && typeof effectiveModel === 'object' && (effectiveModel as any).id) {
|
|
270
|
+
globalModel = effectiveModel as Model<any>;
|
|
271
|
+
} else {
|
|
272
|
+
globalModel = resolveModel(
|
|
273
|
+
globalRegistry,
|
|
274
|
+
typeof effectiveModel === 'string' ? effectiveModel : undefined,
|
|
275
|
+
parsedProvider,
|
|
276
|
+
globalApiKey
|
|
277
|
+
);
|
|
278
|
+
}
|
|
257
279
|
|
|
258
280
|
// Use the global container to ensure internal services can resolve dependencies
|
|
259
281
|
globalContainer = getServiceContainer();
|