localpi 0.6.0 → 0.6.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.
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<img src="assets/cover.svg" alt="localpi: an unopinionated Pi distribution that makes it easy to test and work with small local models on constrained systems" width="880">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
Localpi is an unopinionated Pi distribution that makes it easy to test and work with small local models on constrained systems.
|
|
7
|
+
Localpi is an unopinionated [Pi](https://pi.dev) distribution that makes it easy to test and work with small local models on constrained systems.
|
|
8
8
|
|
|
9
9
|
By default, Localpi discovers available local providers, lets you choose when more than one model is loaded, points Pi at the selected model, and writes Pi config for the other discovered models so `/model` can switch among them during the session.
|
|
10
10
|
|
|
@@ -216,9 +216,10 @@ Approval still works: the adapter forwards Pi's extension dialogs to the ACP cli
|
|
|
216
216
|
asks before a tool call runs. The adapter does not pass `--no-extensions`, so Pi extension discovery
|
|
217
217
|
stays on.
|
|
218
218
|
|
|
219
|
-
Pi has no ACP mode of its own. ACP support comes from
|
|
220
|
-
|
|
221
|
-
different adapter
|
|
219
|
+
Pi has no ACP mode of its own. ACP support comes from
|
|
220
|
+
[`pi-acp`](https://github.com/svkozak/pi-acp) (MIT), which `package.json` pins to an exact version,
|
|
221
|
+
and localpi never vendors its source. Set `LOCALPI_ACP_ADAPTER` to a path to run a different adapter
|
|
222
|
+
build.
|
|
222
223
|
|
|
223
224
|
## Continue On Truncation
|
|
224
225
|
|
|
@@ -523,6 +524,7 @@ demowall record --session demowall-<timestamp> --out demo.mp4 --seconds 60
|
|
|
523
524
|
- `--max-tokens <n>`: generated model max output tokens
|
|
524
525
|
- `--continue-on-truncation <n>`: continue a reply cut off by the output limit, up to `n` times. Off by default, and `LOCALPI_CONTINUE_ON_TRUNCATION=<n>` sets the same limit
|
|
525
526
|
- `--base-url <url>`: OpenAI-compatible endpoint for LM Studio or custom endpoints
|
|
527
|
+
- `--api-key <value>`: Pi provider API key for this run. A literal value, an environment reference such as `${NAME}`, or a `!command`. Default: `local`. `LOCALPI_API_KEY` sets the same value
|
|
526
528
|
- `--server-command <path>`: `llama-server` executable path
|
|
527
529
|
- `--llama-server <path>`: alias for `--server-command`
|
|
528
530
|
- `--host <host>`: managed `llama-server` host. Default: `127.0.0.1`
|
|
@@ -582,6 +584,7 @@ explicit `PI_OFFLINE=0` or `PI_OFFLINE=1` always wins.
|
|
|
582
584
|
- `LOCALPI_MODEL`
|
|
583
585
|
- `LOCALPI_PROVIDER`
|
|
584
586
|
- `LOCALPI_BASE_URL`
|
|
587
|
+
- `LOCALPI_API_KEY`
|
|
585
588
|
- `LOCALPI_PROVIDERS_FILE`
|
|
586
589
|
- `LOCALPI_MODEL_PROFILE`
|
|
587
590
|
- `LOCALPI_MODEL_REASONING`
|
|
@@ -669,6 +672,20 @@ Model capability profiles can fill in metadata that OpenAI-compatible servers do
|
|
|
669
672
|
|
|
670
673
|
`LOCALPAGER_AGENT_PROFILE`, `LOCALPAGER_AGENT_REASONING`, and `LOCALPAGER_AGENT_THINKING_FORMAT` are accepted as aliases so LocalPager Agent can pass the same profile metadata through to localpi.
|
|
671
674
|
|
|
675
|
+
## Related Projects
|
|
676
|
+
|
|
677
|
+
- [Pi](https://pi.dev) is the coding agent this distribution launches. Pi owns model detection, the
|
|
678
|
+
tool loop, streaming, slash commands, and the session. Its source is
|
|
679
|
+
[earendil-works/pi](https://github.com/earendil-works/pi).
|
|
680
|
+
- [pi-factory](https://github.com/osolmaz/pi-factory) builds the Pi launch plan, the launch
|
|
681
|
+
environment, and the runtime config a session uses.
|
|
682
|
+
- [pi-demo-mode](https://github.com/osolmaz/pi-demo-mode) is the shared extension behind demo mode.
|
|
683
|
+
- [pi-acp](https://github.com/svkozak/pi-acp) is the adapter that ACP mode pins, for the
|
|
684
|
+
[Agent Client Protocol](https://agentclientprotocol.com). Localpi keeps no copy of its source.
|
|
685
|
+
- Inference stacks: [llama.cpp](https://github.com/ggml-org/llama.cpp) and its `llama-server`,
|
|
686
|
+
[LM Studio](https://lmstudio.ai), [vLLM](https://github.com/vllm-project/vllm),
|
|
687
|
+
[SGLang](https://github.com/sgl-project/sglang), and [Ollama](https://ollama.com).
|
|
688
|
+
|
|
672
689
|
## Development
|
|
673
690
|
|
|
674
691
|
```bash
|
|
@@ -19,6 +19,7 @@ export function defaultOptions() {
|
|
|
19
19
|
return {
|
|
20
20
|
runtime: parseRuntime(envString("LOCALPI_RUNTIME", "auto")),
|
|
21
21
|
baseUrl: envOptionalBaseUrl("LOCALPI_BASE_URL"),
|
|
22
|
+
apiKey: envString("LOCALPI_API_KEY", "local"),
|
|
22
23
|
model: process.env["LOCALPI_MODEL"],
|
|
23
24
|
provider: process.env["LOCALPI_PROVIDER"],
|
|
24
25
|
customProviderId: envString("LOCALPI_PROVIDER_ID", "local-openai"),
|
|
@@ -100,6 +101,8 @@ export function usage() {
|
|
|
100
101
|
" --provider <id> catalog provider id to use",
|
|
101
102
|
" --model <alias|id|path> model alias, backend id, or GGUF path",
|
|
102
103
|
" --base-url <url> OpenAI-compatible endpoint",
|
|
104
|
+
" --api-key <value> Pi provider API key: a literal, ${NAME}, or !command",
|
|
105
|
+
" (LOCALPI_API_KEY=<value>, default: local)",
|
|
103
106
|
" --ctx <n> model context window",
|
|
104
107
|
" --context-window <n> alias for --ctx",
|
|
105
108
|
" --max-tokens <n> generated model max output tokens",
|
|
@@ -189,6 +192,7 @@ const booleanFlagUpdaters = {
|
|
|
189
192
|
const valueFlagUpdaters = {
|
|
190
193
|
"--runtime": (options, value) => ({ ...options, runtime: parseRuntime(value) }),
|
|
191
194
|
"--base-url": (options, value) => ({ ...options, baseUrl: normalizeBaseUrl(value) }),
|
|
195
|
+
"--api-key": (options, value) => ({ ...options, apiKey: value }),
|
|
192
196
|
"--model": (options, value) => ({ ...options, model: value }),
|
|
193
197
|
"--provider": (options, value) => ({ ...options, provider: value }),
|
|
194
198
|
"--provider-id": (options, value) => ({ ...options, customProviderId: value }),
|
package/dist/src/pi/app.js
CHANGED
|
@@ -86,7 +86,7 @@ function providersForConnection(options, connection) {
|
|
|
86
86
|
id: group.providerId,
|
|
87
87
|
baseUrl: group.baseUrl,
|
|
88
88
|
api: "openai-completions",
|
|
89
|
-
apiKey:
|
|
89
|
+
apiKey: options.apiKey,
|
|
90
90
|
compat: {
|
|
91
91
|
supportsDeveloperRole: false,
|
|
92
92
|
supportsReasoningEffort: false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function startupModelSelectorExtensionSource(options) {
|
|
2
2
|
const startupModelsSource = JSON.stringify(options.models);
|
|
3
|
-
return `import type { ExtensionAPI,
|
|
3
|
+
return `import type { ExtensionAPI, ModelRegistry, ModelRuntime } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { ModelSelectorComponent } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
|
|
6
6
|
type SelectedModel = Parameters<ExtensionAPI["setModel"]>[0];
|
|
@@ -22,20 +22,16 @@ export default function localpiStartupModelSelector(pi: ExtensionAPI): void {
|
|
|
22
22
|
const scopedModels = selectableModels.map((model) => ({ model }));
|
|
23
23
|
|
|
24
24
|
opened = true;
|
|
25
|
-
const selected = await ctx.ui.custom<SelectedModel | undefined>((tui, _theme, _keybindings, done) =>
|
|
26
|
-
|
|
27
|
-
setDefaultModelAndProvider: () => {}
|
|
28
|
-
} as unknown as SettingsManager;
|
|
29
|
-
return new ModelSelectorComponent(
|
|
25
|
+
const selected = await ctx.ui.custom<SelectedModel | undefined>((tui, _theme, _keybindings, done) =>
|
|
26
|
+
new ModelSelectorComponent(
|
|
30
27
|
tui,
|
|
31
28
|
ctx.model,
|
|
32
|
-
|
|
33
|
-
startupModelRegistry(ctx.modelRegistry) as typeof ctx.modelRegistry,
|
|
29
|
+
startupModelRuntime(ctx.modelRegistry),
|
|
34
30
|
scopedModels,
|
|
35
|
-
(model) => done(model),
|
|
31
|
+
(model: SelectedModel) => done(model),
|
|
36
32
|
() => done(undefined)
|
|
37
|
-
)
|
|
38
|
-
|
|
33
|
+
)
|
|
34
|
+
);
|
|
39
35
|
|
|
40
36
|
if (selected === undefined) {
|
|
41
37
|
return;
|
|
@@ -54,21 +50,20 @@ function startupAvailableModels(registry: {
|
|
|
54
50
|
return registry.getAvailable().filter((model) => startupModelKeys.has(modelKey(model)));
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
refresh: () => registry.refresh(),
|
|
65
|
-
getError: () => registry.getError(),
|
|
66
|
-
getAvailable: () => startupAvailableModels(registry),
|
|
67
|
-
find: (provider, modelId) => {
|
|
53
|
+
// The selector reads a ModelRuntime, which extensions cannot reach. It only calls
|
|
54
|
+
// getAvailableSnapshot, getModel, getError, and refresh, so this view answers
|
|
55
|
+
// those from the registry and hides every model outside the startup list.
|
|
56
|
+
function startupModelRuntime(registry: ModelRegistry): ModelRuntime {
|
|
57
|
+
const view = {
|
|
58
|
+
getAvailableSnapshot: () => startupAvailableModels(registry),
|
|
59
|
+
getModel: (provider: string, modelId: string) => {
|
|
68
60
|
const model = registry.find(provider, modelId);
|
|
69
61
|
return model !== undefined && startupModelKeys.has(modelKey(model)) ? model : undefined;
|
|
70
|
-
}
|
|
62
|
+
},
|
|
63
|
+
getError: () => registry.getError(),
|
|
64
|
+
refresh: (options?: Parameters<ModelRegistry["refresh"]>[0]) => registry.refresh(options)
|
|
71
65
|
};
|
|
66
|
+
return view as unknown as ModelRuntime;
|
|
72
67
|
}
|
|
73
68
|
|
|
74
69
|
function modelKey(model: { readonly provider: string; readonly id: string }): string {
|
|
@@ -110,6 +110,7 @@ Localpi:
|
|
|
110
110
|
- can use `--provider <id>` to name the generated Pi provider
|
|
111
111
|
- uses `/v1/models` for discovery
|
|
112
112
|
- avoids assuming it can start, stop, or unload the backend
|
|
113
|
+
- writes the `--api-key` value as the generated Pi provider key, exactly as given, so an environment reference such as `${HF_TOKEN}` or a `!command` keeps the secret out of the Pi config. The default is `local`, which local engines accept and ignore
|
|
113
114
|
|
|
114
115
|
### Configured Providers
|
|
115
116
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "localpi",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Swiss army knife for running Pi with local inference engines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"check": "npm run format && npm run lint && npm run typecheck && npm test && npm run build"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@earendil-works/pi-coding-agent": "^0.87.
|
|
44
|
+
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
45
45
|
"@eslint/js": "^9.0.0",
|
|
46
46
|
"@stryker-mutator/core": "^9.6.1",
|
|
47
47
|
"@stryker-mutator/typescript-checker": "^9.6.1",
|