@vtstech/pi-api 1.0.3 → 1.0.4-1
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 +46 -0
- package/api.js +71 -91
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @vtstech/pi-api
|
|
2
|
+
|
|
3
|
+
API Mode Switcher extension for the [Pi Coding Agent](https://github.com/badlogic/pi-mono).
|
|
4
|
+
|
|
5
|
+
Runtime switching of API modes, base URLs, thinking settings, and compat flags in `models.json`. Supports all 10 Pi API modes.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi install "npm:@vtstech/pi-api"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/api Show current provider config (mode, URL, compat flags)
|
|
17
|
+
/api mode <mode> Switch API mode (partial match supported)
|
|
18
|
+
/api url <url> Switch base URL
|
|
19
|
+
/api think on|off|auto Toggle thinking for all models in provider
|
|
20
|
+
/api compat <key> View compat flags
|
|
21
|
+
/api compat <key> <val> Set compat flag
|
|
22
|
+
/api modes List all 10 supported API modes
|
|
23
|
+
/api providers List all configured providers
|
|
24
|
+
/api reload Hint to run /reload
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Supported API Modes
|
|
28
|
+
|
|
29
|
+
`anthropic-messages` · `openai-completions` · `openai-responses` · `azure-openai-responses` · `openai-codex-responses` · `mistral-conversations` · `google-generative-ai` · `google-gemini-cli` · `google-vertex` · `bedrock-converse-stream`
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- Partial mode matching — `/api mode openai-r` matches `openai-responses`
|
|
34
|
+
- Auto-detect local provider — targets the first `localhost`/`ollama` provider by default
|
|
35
|
+
- Batch thinking toggle — set `reasoning: true/false` across all models at once
|
|
36
|
+
- Compat flag management — get/set `supportsDeveloperRole`, `thinkingFormat`, `maxTokensField`, etc.
|
|
37
|
+
- Tab-completion for sub-commands
|
|
38
|
+
|
|
39
|
+
## Links
|
|
40
|
+
|
|
41
|
+
- [Full Documentation](https://github.com/VTSTech/pi-coding-agent#api-mode-switcher-apits)
|
|
42
|
+
- [Changelog](https://github.com/VTSTech/pi-coding-agent/blob/main/CHANGELOG.md)
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT — [VTSTech](https://www.vts-tech.org)
|
package/api.js
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __export = (target, all) => {
|
|
6
|
-
for (var name in all)
|
|
7
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
-
};
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
for (let key of __getOwnPropNames(from))
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
-
}
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
-
|
|
19
1
|
// .build-npm/api/api.temp.ts
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
default: () => api_temp_default
|
|
23
|
-
});
|
|
24
|
-
module.exports = __toCommonJS(api_temp_exports);
|
|
25
|
-
var import_format = require("@vtstech/pi-shared/format");
|
|
26
|
-
var import_ollama = require("@vtstech/pi-shared/ollama");
|
|
2
|
+
import { section, ok, info, warn } from "@vtstech/pi-shared/format";
|
|
3
|
+
import { readModelsJson, writeModelsJson, getOllamaBaseUrl } from "@vtstech/pi-shared/ollama";
|
|
27
4
|
var API_MODES = {
|
|
28
5
|
"anthropic-messages": "Anthropic Claude API and compatibles",
|
|
29
6
|
"openai-completions": "OpenAI Chat Completions API and compatibles",
|
|
@@ -87,7 +64,7 @@ function api_temp_default(pi) {
|
|
|
87
64
|
const parts = args.trim().split(/\s+/);
|
|
88
65
|
const sub = parts[0]?.toLowerCase() || "";
|
|
89
66
|
const rest = parts.slice(1).join(" ");
|
|
90
|
-
const config =
|
|
67
|
+
const config = readModelsJson();
|
|
91
68
|
const provider = resolveProvider(config);
|
|
92
69
|
if (!provider) {
|
|
93
70
|
ctx.ui.notify("No providers found in models.json", "error");
|
|
@@ -122,22 +99,22 @@ function api_temp_default(pi) {
|
|
|
122
99
|
const modelCount = p.models?.length || 0;
|
|
123
100
|
const firstModel = p.models?.[0]?.id || "none";
|
|
124
101
|
const lines = [branding];
|
|
125
|
-
lines.push(
|
|
126
|
-
lines.push(
|
|
127
|
-
lines.push(
|
|
128
|
-
lines.push(
|
|
129
|
-
lines.push(
|
|
130
|
-
lines.push(
|
|
102
|
+
lines.push(section("CURRENT PROVIDER CONFIG"));
|
|
103
|
+
lines.push(info(`Provider: ${provider.name}`));
|
|
104
|
+
lines.push(info(`API mode: ${p.api || "(not set)"}`));
|
|
105
|
+
lines.push(info(`Base URL: ${p.baseUrl || "(not set)"}`));
|
|
106
|
+
lines.push(info(`API key: ${p.apiKey ? "\u2022\u2022\u2022\u2022" + String(p.apiKey).slice(-4) : "(not set)"}`));
|
|
107
|
+
lines.push(info(`Models: ${modelCount} (first: ${firstModel})`));
|
|
131
108
|
if (Object.keys(compat).length > 0) {
|
|
132
|
-
lines.push(
|
|
109
|
+
lines.push(section("COMPAT FLAGS"));
|
|
133
110
|
for (const [key, value] of Object.entries(compat)) {
|
|
134
|
-
lines.push(
|
|
111
|
+
lines.push(info(` ${key}: ${JSON.stringify(value)}`));
|
|
135
112
|
}
|
|
136
113
|
}
|
|
137
|
-
const ollamaBase =
|
|
138
|
-
lines.push(
|
|
139
|
-
lines.push(
|
|
140
|
-
lines.push(
|
|
114
|
+
const ollamaBase = getOllamaBaseUrl();
|
|
115
|
+
lines.push(section("RESOLVED"));
|
|
116
|
+
lines.push(info(`Ollama base: ${ollamaBase}`));
|
|
117
|
+
lines.push(info(`(strip /v1 \u2192 ${ollamaBase})`));
|
|
141
118
|
pi.sendMessage({
|
|
142
119
|
customType: "api-config",
|
|
143
120
|
content: lines.join("\n"),
|
|
@@ -158,7 +135,7 @@ function api_temp_default(pi) {
|
|
|
158
135
|
ctx.ui.notify(`Unknown API mode: "${mode}". Use /api modes to list available modes.`, "error");
|
|
159
136
|
return;
|
|
160
137
|
}
|
|
161
|
-
const config =
|
|
138
|
+
const config = readModelsJson();
|
|
162
139
|
const provider = config.providers[providerName];
|
|
163
140
|
if (!provider) {
|
|
164
141
|
ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
|
|
@@ -166,14 +143,14 @@ function api_temp_default(pi) {
|
|
|
166
143
|
}
|
|
167
144
|
const oldMode = provider.api || "(not set)";
|
|
168
145
|
provider.api = matched;
|
|
169
|
-
|
|
146
|
+
writeModelsJson(config);
|
|
170
147
|
const lines = [branding];
|
|
171
|
-
lines.push(
|
|
172
|
-
lines.push(
|
|
173
|
-
lines.push(
|
|
174
|
-
lines.push(
|
|
175
|
-
lines.push(
|
|
176
|
-
lines.push(
|
|
148
|
+
lines.push(section("API MODE CHANGED"));
|
|
149
|
+
lines.push(ok(`Provider: ${providerName}`));
|
|
150
|
+
lines.push(info(`Old mode: ${oldMode}`));
|
|
151
|
+
lines.push(ok(`New mode: ${matched}`));
|
|
152
|
+
lines.push(info(`Description: ${API_MODES[matched]}`));
|
|
153
|
+
lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
|
|
177
154
|
pi.sendMessage({
|
|
178
155
|
customType: "api-mode-changed",
|
|
179
156
|
content: lines.join("\n"),
|
|
@@ -190,7 +167,7 @@ function api_temp_default(pi) {
|
|
|
190
167
|
if (!normalizedUrl.startsWith("http")) {
|
|
191
168
|
normalizedUrl = "http://" + normalizedUrl;
|
|
192
169
|
}
|
|
193
|
-
const config =
|
|
170
|
+
const config = readModelsJson();
|
|
194
171
|
const provider = config.providers[providerName];
|
|
195
172
|
if (!provider) {
|
|
196
173
|
ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
|
|
@@ -198,13 +175,13 @@ function api_temp_default(pi) {
|
|
|
198
175
|
}
|
|
199
176
|
const oldUrl = provider.baseUrl || "(not set)";
|
|
200
177
|
provider.baseUrl = normalizedUrl;
|
|
201
|
-
|
|
178
|
+
writeModelsJson(config);
|
|
202
179
|
const lines = [branding];
|
|
203
|
-
lines.push(
|
|
204
|
-
lines.push(
|
|
205
|
-
lines.push(
|
|
206
|
-
lines.push(
|
|
207
|
-
lines.push(
|
|
180
|
+
lines.push(section("BASE URL CHANGED"));
|
|
181
|
+
lines.push(ok(`Provider: ${providerName}`));
|
|
182
|
+
lines.push(info(`Old URL: ${oldUrl}`));
|
|
183
|
+
lines.push(ok(`New URL: ${normalizedUrl}`));
|
|
184
|
+
lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
|
|
208
185
|
pi.sendMessage({
|
|
209
186
|
customType: "api-url-changed",
|
|
210
187
|
content: lines.join("\n"),
|
|
@@ -217,7 +194,7 @@ function api_temp_default(pi) {
|
|
|
217
194
|
ctx.ui.notify("Usage: /api think <on|off|auto>", "error");
|
|
218
195
|
return;
|
|
219
196
|
}
|
|
220
|
-
const config =
|
|
197
|
+
const config = readModelsJson();
|
|
221
198
|
const provider = config.providers[providerName];
|
|
222
199
|
if (!provider) {
|
|
223
200
|
ctx.ui.notify(`Provider "${providerName}" not found in models.json`, "error");
|
|
@@ -249,16 +226,16 @@ function api_temp_default(pi) {
|
|
|
249
226
|
ctx.ui.notify("Invalid value. Use: on, off, or auto", "error");
|
|
250
227
|
return;
|
|
251
228
|
}
|
|
252
|
-
|
|
229
|
+
writeModelsJson(config);
|
|
253
230
|
const lines = [branding];
|
|
254
|
-
lines.push(
|
|
255
|
-
lines.push(
|
|
256
|
-
lines.push(
|
|
257
|
-
lines.push(
|
|
231
|
+
lines.push(section("THINKING MODE"));
|
|
232
|
+
lines.push(info(`Provider: ${providerName}`));
|
|
233
|
+
lines.push(info(`Mode: ${valLower}`));
|
|
234
|
+
lines.push(info(`Affected ${models.length} model(s):`));
|
|
258
235
|
for (const model of models) {
|
|
259
|
-
lines.push(
|
|
236
|
+
lines.push(info(` ${(model.id || "?").padEnd(40)} reasoning: ${model.reasoning ? "true" : "false"}`));
|
|
260
237
|
}
|
|
261
|
-
lines.push(
|
|
238
|
+
lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
|
|
262
239
|
pi.sendMessage({
|
|
263
240
|
customType: "api-think-changed",
|
|
264
241
|
content: lines.join("\n"),
|
|
@@ -271,7 +248,7 @@ function api_temp_default(pi) {
|
|
|
271
248
|
const key = parts[0];
|
|
272
249
|
const value = parts.slice(1).join(" ");
|
|
273
250
|
if (!key) {
|
|
274
|
-
const config2 =
|
|
251
|
+
const config2 = readModelsJson();
|
|
275
252
|
const provider2 = config2.providers[providerName];
|
|
276
253
|
if (!provider2) {
|
|
277
254
|
ctx.ui.notify(`Provider "${providerName}" not found`, "error");
|
|
@@ -279,20 +256,20 @@ function api_temp_default(pi) {
|
|
|
279
256
|
}
|
|
280
257
|
const compat = provider2.compat || {};
|
|
281
258
|
const lines2 = [branding];
|
|
282
|
-
lines2.push(
|
|
259
|
+
lines2.push(section("COMPAT FLAGS"));
|
|
283
260
|
if (Object.keys(compat).length === 0) {
|
|
284
|
-
lines2.push(
|
|
261
|
+
lines2.push(info("No compat flags set"));
|
|
285
262
|
} else {
|
|
286
263
|
for (const [k, v] of Object.entries(compat)) {
|
|
287
264
|
const flag = COMPAT_FLAGS[k];
|
|
288
|
-
lines2.push(
|
|
265
|
+
lines2.push(info(` ${k}: ${JSON.stringify(v)}${flag ? ` \u2014 ${flag.description}` : ""}`));
|
|
289
266
|
}
|
|
290
267
|
}
|
|
291
|
-
lines2.push(
|
|
268
|
+
lines2.push(section("AVAILABLE FLAGS"));
|
|
292
269
|
for (const [k, flag] of Object.entries(COMPAT_FLAGS)) {
|
|
293
|
-
lines2.push(
|
|
270
|
+
lines2.push(info(` ${k} = <${flag.values.join(" | ")}> \u2014 ${flag.description}`));
|
|
294
271
|
}
|
|
295
|
-
lines2.push(
|
|
272
|
+
lines2.push(info("Usage: /api compat <key> <value>"));
|
|
296
273
|
pi.sendMessage({
|
|
297
274
|
customType: "api-compat-flags",
|
|
298
275
|
content: lines2.join("\n"),
|
|
@@ -301,7 +278,7 @@ function api_temp_default(pi) {
|
|
|
301
278
|
return;
|
|
302
279
|
}
|
|
303
280
|
if (!value) {
|
|
304
|
-
const config2 =
|
|
281
|
+
const config2 = readModelsJson();
|
|
305
282
|
const provider2 = config2.providers[providerName];
|
|
306
283
|
if (!provider2) {
|
|
307
284
|
ctx.ui.notify(`Provider "${providerName}" not found`, "error");
|
|
@@ -311,7 +288,7 @@ function api_temp_default(pi) {
|
|
|
311
288
|
ctx.ui.notify(`${key} = ${current !== void 0 ? JSON.stringify(current) : "(not set)"}`, "info");
|
|
312
289
|
return;
|
|
313
290
|
}
|
|
314
|
-
const config =
|
|
291
|
+
const config = readModelsJson();
|
|
315
292
|
const provider = config.providers[providerName];
|
|
316
293
|
if (!provider) {
|
|
317
294
|
ctx.ui.notify(`Provider "${providerName}" not found`, "error");
|
|
@@ -330,14 +307,14 @@ function api_temp_default(pi) {
|
|
|
330
307
|
}
|
|
331
308
|
const oldValue = provider.compat[key];
|
|
332
309
|
provider.compat[key] = parsedValue;
|
|
333
|
-
|
|
310
|
+
writeModelsJson(config);
|
|
334
311
|
const lines = [branding];
|
|
335
|
-
lines.push(
|
|
336
|
-
lines.push(
|
|
337
|
-
lines.push(
|
|
338
|
-
lines.push(
|
|
339
|
-
lines.push(
|
|
340
|
-
lines.push(
|
|
312
|
+
lines.push(section("COMPAT FLAG SET"));
|
|
313
|
+
lines.push(ok(`Provider: ${providerName}`));
|
|
314
|
+
lines.push(info(`Key: ${key}`));
|
|
315
|
+
lines.push(info(`Old value: ${oldValue !== void 0 ? JSON.stringify(oldValue) : "(not set)"}`));
|
|
316
|
+
lines.push(ok(`New value: ${JSON.stringify(parsedValue)}`));
|
|
317
|
+
lines.push(warn("Run /api reload or /reload to apply changes in Pi"));
|
|
341
318
|
pi.sendMessage({
|
|
342
319
|
customType: "api-compat-set",
|
|
343
320
|
content: lines.join("\n"),
|
|
@@ -347,11 +324,11 @@ function api_temp_default(pi) {
|
|
|
347
324
|
}
|
|
348
325
|
function reloadConfig(ctx) {
|
|
349
326
|
const lines = [branding];
|
|
350
|
-
lines.push(
|
|
351
|
-
lines.push(
|
|
352
|
-
lines.push(
|
|
353
|
-
lines.push(
|
|
354
|
-
lines.push(
|
|
327
|
+
lines.push(section("RELOAD"));
|
|
328
|
+
lines.push(ok("models.json has been modified"));
|
|
329
|
+
lines.push(info("To apply changes, run Pi's built-in command:"));
|
|
330
|
+
lines.push(info(" /reload"));
|
|
331
|
+
lines.push(warn("This will reload all provider configurations from models.json"));
|
|
355
332
|
pi.sendMessage({
|
|
356
333
|
customType: "api-reload",
|
|
357
334
|
content: lines.join("\n"),
|
|
@@ -361,17 +338,17 @@ function api_temp_default(pi) {
|
|
|
361
338
|
}
|
|
362
339
|
function listModes() {
|
|
363
340
|
const lines = [branding];
|
|
364
|
-
lines.push(
|
|
365
|
-
const config =
|
|
341
|
+
lines.push(section("SUPPORTED API MODES"));
|
|
342
|
+
const config = readModelsJson();
|
|
366
343
|
const provider = resolveProvider(config);
|
|
367
344
|
const currentMode = provider?.config?.api || "(not set)";
|
|
368
345
|
for (const [mode, description] of Object.entries(API_MODES)) {
|
|
369
346
|
const isActive = mode === currentMode;
|
|
370
|
-
const marker = isActive ?
|
|
371
|
-
lines.push(
|
|
347
|
+
const marker = isActive ? ok(" \u25C0 current") : "";
|
|
348
|
+
lines.push(info(` ${mode.padEnd(30)} ${description}${marker}`));
|
|
372
349
|
}
|
|
373
|
-
lines.push(
|
|
374
|
-
lines.push(
|
|
350
|
+
lines.push(info(""));
|
|
351
|
+
lines.push(info("Usage: /api mode <mode>"));
|
|
375
352
|
pi.sendMessage({
|
|
376
353
|
customType: "api-modes",
|
|
377
354
|
content: lines.join("\n"),
|
|
@@ -380,14 +357,14 @@ function api_temp_default(pi) {
|
|
|
380
357
|
}
|
|
381
358
|
function listProviders(config) {
|
|
382
359
|
const lines = [branding];
|
|
383
|
-
lines.push(
|
|
360
|
+
lines.push(section("PROVIDERS"));
|
|
384
361
|
for (const [name, provider] of Object.entries(config.providers)) {
|
|
385
362
|
const modelCount = provider.models?.length || 0;
|
|
386
363
|
const url = provider.baseUrl || "(no URL)";
|
|
387
364
|
const api = provider.api || "(no mode)";
|
|
388
365
|
const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || name === "ollama";
|
|
389
|
-
lines.push(
|
|
390
|
-
lines.push(
|
|
366
|
+
lines.push(info(` ${name}${isLocal ? " (local)" : ""}`));
|
|
367
|
+
lines.push(info(` API: ${api} | URL: ${url} | Models: ${modelCount}`));
|
|
391
368
|
}
|
|
392
369
|
pi.sendMessage({
|
|
393
370
|
customType: "api-providers",
|
|
@@ -409,3 +386,6 @@ function api_temp_default(pi) {
|
|
|
409
386
|
}
|
|
410
387
|
});
|
|
411
388
|
}
|
|
389
|
+
export {
|
|
390
|
+
api_temp_default as default
|
|
391
|
+
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtstech/pi-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4-1",
|
|
4
4
|
"description": "API Mode Switcher extension for Pi Coding Agent",
|
|
5
5
|
"main": "api.js",
|
|
6
6
|
"keywords": ["pi-package", "pi-extensions"],
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"access": "public",
|
|
9
|
+
"type": "module",
|
|
9
10
|
"author": "VTSTech",
|
|
10
11
|
"homepage": "https://www.vts-tech.org",
|
|
11
12
|
"repository": {
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"url": "https://github.com/VTSTech/pi-coding-agent"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
|
-
"@vtstech/pi-shared": "1.0.
|
|
17
|
+
"@vtstech/pi-shared": "1.0.4-1"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
19
20
|
"@mariozechner/pi-coding-agent": ">=0.66"
|